mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-05 11:30:29 -04:00
Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2
This commit is contained in:
committed by
Anthony Dresser
parent
3603f55d97
commit
7f1d8fc32f
@@ -27,7 +27,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { dirname, basename } from 'vs/base/common/resources';
|
||||
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { WorkbenchAsyncDataTree, ResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -416,9 +416,9 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
return element.label ? element.label.label : '';
|
||||
}
|
||||
},
|
||||
getWidgetAriaLabel: () => this.title
|
||||
},
|
||||
ariaLabel: this.title,
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (item: ITreeItem) => {
|
||||
return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined);
|
||||
@@ -451,7 +451,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
}));
|
||||
this.tree.setInput(this.root).then(() => this.updateContentAreas());
|
||||
|
||||
const customTreeNavigator = ResourceNavigator.createTreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
|
||||
const customTreeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
|
||||
this._register(customTreeNavigator);
|
||||
this._register(customTreeNavigator.onDidOpenResource(e => {
|
||||
if (!e.browserEvent) {
|
||||
|
||||
@@ -28,7 +28,8 @@ class AccountsStatusBarContributions extends Disposable implements IWorkbenchCon
|
||||
this._register(
|
||||
this.statusbarService.addEntry({
|
||||
command: 'workbench.actions.modal.linkedAccount',
|
||||
text: '$(person-filled)'
|
||||
text: '$(person-filled)',
|
||||
ariaLabel: 'Accounts'
|
||||
},
|
||||
'status.accountList',
|
||||
localize('status.problems', "Problems"),
|
||||
|
||||
@@ -30,6 +30,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
ConnectionStatusbarItem.ID,
|
||||
localize('status.connection.status', "Connection Status"),
|
||||
@@ -84,7 +85,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
|
||||
}
|
||||
|
||||
this.statusItem.update({
|
||||
text, tooltip
|
||||
text, ariaLabel: text, tooltip
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): void {
|
||||
|
||||
@@ -88,11 +88,13 @@ export class EditDataEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
if (_editorService) {
|
||||
_editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
_editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IModeService private readonly modeService: IModeService
|
||||
) {
|
||||
this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group));
|
||||
this.editorOpeningListener = this.editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => this.onEditorOpening(editor, options, group)
|
||||
});
|
||||
}
|
||||
|
||||
private onEditorOpening(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined {
|
||||
|
||||
@@ -194,7 +194,7 @@ class MockEditorService extends TestEditorService {
|
||||
fireOpenEditor(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) {
|
||||
for (const handler of this.overridenOpens) {
|
||||
let response: IOpenEditorOverride | undefined;
|
||||
if (response = handler(editor, options, group)) {
|
||||
if (response = handler.open(editor, options, group)) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { visualizerExtensions } from 'sql/workbench/contrib/extensions/common/constants';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { InstallRecommendedExtensionsByScenarioAction, ShowRecommendedExtensionsByScenarioAction } from 'sql/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
||||
|
||||
export class ScenarioRecommendations extends ExtensionRecommendations {
|
||||
|
||||
readonly _recommendations: ExtensionRecommendation[] = [];
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
|
||||
// this._recommendations = productService.recommendedExtensionsByScenario.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
|
||||
protected async doActivate(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
promptRecommendedExtensionsByScenario(scenarioType: string): void {
|
||||
const storageKey = 'extensionAssistant/RecommendationsIgnore/' + scenarioType;
|
||||
|
||||
if (this.storageService.getBoolean(storageKey, StorageScope.GLOBAL, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const visualizerExtensionNotificationService = 'VisualizerExtensionNotificationService';
|
||||
|
||||
let recommendationMessage = localize('ExtensionsRecommended', "Azure Data Studio has extension recommendations.");
|
||||
if (scenarioType === visualizerExtensions) {
|
||||
recommendationMessage = localize('VisualizerExtensionsRecommended', "Azure Data Studio has extension recommendations for data visualization.\nOnce installed, you can select the Visualizer icon to visualize your query results.");
|
||||
}
|
||||
Promise.all([this.getRecommendedExtensionsByScenario(scenarioType), this.extensionManagementService.getInstalled(ExtensionType.User)]).then(([recommendations, localExtensions]) => {
|
||||
if (!recommendations.every(rec => { return localExtensions.findIndex(local => local.identifier.id.toLocaleLowerCase() === rec.extensionId.toLocaleLowerCase()) !== -1; })) {
|
||||
return new Promise<void>(c => {
|
||||
this.notificationService.prompt(
|
||||
Severity.Info,
|
||||
recommendationMessage,
|
||||
[{
|
||||
label: localize('installAll', "Install All"),
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'InstallButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
const installAllAction = this.instantiationService.createInstance(InstallRecommendedExtensionsByScenarioAction, scenarioType, recommendations);
|
||||
installAllAction.run();
|
||||
installAllAction.dispose();
|
||||
}
|
||||
}, {
|
||||
label: localize('showRecommendations', "Show Recommendations"),
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'ShowRecommendationsButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
const showAction = this.instantiationService.createInstance(ShowRecommendedExtensionsByScenarioAction, scenarioType);
|
||||
showAction.run();
|
||||
showAction.dispose();
|
||||
c(undefined);
|
||||
}
|
||||
}, {
|
||||
label: choiceNever,
|
||||
isSecondary: true,
|
||||
run: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'NeverShowAgainButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
this.storageService.store(storageKey, true, StorageScope.GLOBAL);
|
||||
c(undefined);
|
||||
}
|
||||
}],
|
||||
{
|
||||
sticky: true,
|
||||
onCancel: () => {
|
||||
this.adsTelemetryService.sendActionEvent(
|
||||
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
|
||||
TelemetryKeys.TelemetryAction.Click,
|
||||
'CancelButton',
|
||||
visualizerExtensionNotificationService
|
||||
);
|
||||
c(undefined);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
|
||||
if (!scenarioType) {
|
||||
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
|
||||
}
|
||||
return Promise.resolve((this.productService.recommendedExtensionsByScenario[scenarioType] || [])
|
||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
export class StaticRecommendations extends ExtensionRecommendations {
|
||||
|
||||
readonly _recommendations: ExtensionRecommendation[] = [];
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
@IProductService productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
|
||||
this._recommendations = productService.recommendedExtensions.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
|
||||
protected async doActivate(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
|
||||
searchScope: true,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: true
|
||||
};
|
||||
this._notebookModel.cells.forEach(cell => {
|
||||
this._register(cell.onCellModeChanged((state) => {
|
||||
@@ -450,7 +451,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: true
|
||||
};
|
||||
this._onFindStateChange(changeEvent).catch(e => { onUnexpectedError(e); });
|
||||
}
|
||||
|
||||
@@ -172,11 +172,13 @@ export class ProfilerEditor extends BaseEditor {
|
||||
this._profilerEditorContextKey = CONTEXT_PROFILER_EDITOR.bindTo(this._contextKeyService);
|
||||
|
||||
if (editorService) {
|
||||
editorService.overrideOpenEditor((editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
editorService.overrideOpenEditor({
|
||||
open: (editor, options, group) => {
|
||||
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
|
||||
this.saveEditorViewState();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -502,7 +504,8 @@ export class ProfilerEditor extends BaseEditor {
|
||||
seedSearchStringFromSelection: (controller.getState().searchString.length === 0),
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -288,7 +288,7 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll
|
||||
: localize('ProfilerTableEditor.eventCount', "Events: {0}", this._input.data.getLength());
|
||||
|
||||
this._disposeStatusbarItem();
|
||||
this._statusbarItem = this._statusbarService.addEntry({ text: message }, 'status.eventCount', localize('status.eventCount', "Event Count"), StatusbarAlignment.RIGHT);
|
||||
this._statusbarItem = this._statusbarService.addEntry({ text: message, ariaLabel: message }, 'status.eventCount', localize('status.eventCount', "Event Count"), StatusbarAlignment.RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ export class SqlFlavorStatusbarItem extends Disposable implements IWorkbenchCont
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: nls.localize('changeProvider', "Change SQL language provider"),
|
||||
ariaLabel: nls.localize('changeProvider', "Change SQL language provider"),
|
||||
command: 'sql.action.editor.changeProvider'
|
||||
|
||||
},
|
||||
SqlFlavorStatusbarItem.ID,
|
||||
nls.localize('status.query.flavor', "SQL Language Flavor"),
|
||||
@@ -161,6 +161,7 @@ export class SqlFlavorStatusbarItem extends Disposable implements IWorkbenchCont
|
||||
private updateFlavorElement(text: string): void {
|
||||
const props: IStatusbarEntry = {
|
||||
text,
|
||||
ariaLabel: text,
|
||||
command: 'sql.action.editor.changeProvider'
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ export class TimeElapsedStatusBarContributions extends Disposable implements IWo
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
TimeElapsedStatusBarContributions.ID,
|
||||
localize('status.query.timeElapsed', "Time Elapsed"),
|
||||
@@ -89,20 +90,26 @@ export class TimeElapsedStatusBarContributions extends Disposable implements IWo
|
||||
if (runner.isExecuting) {
|
||||
this.intervalTimer.cancelAndSet(() => {
|
||||
const value = runner.queryStartTime ? Date.now() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
const value = runner.queryStartTime ? Date.now() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
} else {
|
||||
const value = runner.queryStartTime && runner.queryEndTime
|
||||
? runner.queryEndTime.getTime() - runner.queryStartTime.getTime() : 0;
|
||||
const timeString = parseNumAsTimeString(value, false);
|
||||
this.statusItem.update({
|
||||
text: parseNumAsTimeString(value, false)
|
||||
text: timeString,
|
||||
ariaLabel: timeString
|
||||
});
|
||||
}
|
||||
this.show();
|
||||
@@ -126,6 +133,7 @@ export class RowCountStatusBarContributions extends Disposable implements IWorkb
|
||||
this.statusItem = this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: '',
|
||||
ariaLabel: ''
|
||||
},
|
||||
RowCountStatusBarContributions.ID,
|
||||
localize('status.query.rowCount', "Row Count"),
|
||||
@@ -191,7 +199,7 @@ export class RowCountStatusBarContributions extends Disposable implements IWorkb
|
||||
}, 0);
|
||||
}, 0);
|
||||
const text = localize('rowCount', "{0} rows", rowCount.toLocaleString());
|
||||
this.statusItem.update({ text });
|
||||
this.statusItem.update({ text, ariaLabel: text });
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
@@ -211,6 +219,7 @@ export class QueryStatusStatusBarContributions extends Disposable implements IWo
|
||||
this._register(
|
||||
this.statusbarService.addEntry({
|
||||
text: localize('query.status.executing', "Executing query..."),
|
||||
ariaLabel: localize('query.status.executing', "Executing query...")
|
||||
},
|
||||
QueryStatusStatusBarContributions.ID,
|
||||
localize('status.query.status', "Execution Status"),
|
||||
|
||||
@@ -822,6 +822,7 @@ export const EventType = {
|
||||
MOUSE_OUT: 'mouseout',
|
||||
MOUSE_ENTER: 'mouseenter',
|
||||
MOUSE_LEAVE: 'mouseleave',
|
||||
MOUSE_WHEEL: browser.isEdge ? 'mousewheel' : 'wheel',
|
||||
POINTER_UP: 'pointerup',
|
||||
POINTER_DOWN: 'pointerdown',
|
||||
POINTER_MOVE: 'pointermove',
|
||||
|
||||
@@ -197,8 +197,8 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
||||
|
||||
const renderedMarkdown = marked.parse(
|
||||
markdown.supportThemeIcons
|
||||
? markdownEscapeEscapedCodicons(markdown.value)
|
||||
: markdown.value,
|
||||
? markdownEscapeEscapedCodicons(markdown.value || '')
|
||||
: (markdown.value || ''),
|
||||
markedOptions
|
||||
);
|
||||
|
||||
|
||||
@@ -80,15 +80,11 @@ export class StandardMouseEvent implements IMouseEvent {
|
||||
}
|
||||
|
||||
public preventDefault(): void {
|
||||
if (this.browserEvent.preventDefault) {
|
||||
this.browserEvent.preventDefault();
|
||||
}
|
||||
this.browserEvent.preventDefault();
|
||||
}
|
||||
|
||||
public stopPropagation(): void {
|
||||
if (this.browserEvent.stopPropagation) {
|
||||
this.browserEvent.stopPropagation();
|
||||
}
|
||||
this.browserEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,17 +204,13 @@ export class StandardWheelEvent {
|
||||
|
||||
public preventDefault(): void {
|
||||
if (this.browserEvent) {
|
||||
if (this.browserEvent.preventDefault) {
|
||||
this.browserEvent.preventDefault();
|
||||
}
|
||||
this.browserEvent.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public stopPropagation(): void {
|
||||
if (this.browserEvent) {
|
||||
if (this.browserEvent.stopPropagation) {
|
||||
this.browserEvent.stopPropagation();
|
||||
}
|
||||
this.browserEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
|
||||
if (platform.isMacintosh) {
|
||||
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
|
||||
// main mouse button. This is for scenarios where e.g. some interaction forces
|
||||
// main mouse button. This is for scenarios where e.g. some interaction forces
|
||||
// the Ctrl+key to be pressed and hold but the user still wants to interact
|
||||
// with the actions (for example quick access in quick navigation mode).
|
||||
this._register(DOM.addDisposableListener(element, DOM.EventType.CONTEXT_MENU, e => {
|
||||
@@ -276,7 +276,6 @@ export class ActionViewItem extends BaseActionViewItem {
|
||||
this.label = DOM.append(this.element, DOM.$('a.action-label'));
|
||||
}
|
||||
|
||||
|
||||
if (this.label) {
|
||||
if (this._action.id === Separator.ID) {
|
||||
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./aria';
|
||||
import * as nls from 'vs/nls';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
|
||||
@@ -23,7 +22,8 @@ export function setARIAContainer(parent: HTMLElement) {
|
||||
|
||||
statusContainer = document.createElement('div');
|
||||
statusContainer.className = 'monaco-status';
|
||||
statusContainer.setAttribute('role', 'status');
|
||||
statusContainer.setAttribute('role', 'complementary');
|
||||
statusContainer.setAttribute('aria-live', 'polite');
|
||||
statusContainer.setAttribute('aria-atomic', 'true');
|
||||
ariaContainer.appendChild(statusContainer);
|
||||
|
||||
@@ -33,51 +33,30 @@ export function setARIAContainer(parent: HTMLElement) {
|
||||
/**
|
||||
* Given the provided message, will make sure that it is read as alert to screen readers.
|
||||
*/
|
||||
export function alert(msg: string, disableRepeat?: boolean): void {
|
||||
insertMessage(alertContainer, msg, disableRepeat);
|
||||
export function alert(msg: string): void {
|
||||
insertMessage(alertContainer, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the provided message, will make sure that it is read as status to screen readers.
|
||||
*/
|
||||
export function status(msg: string, disableRepeat?: boolean): void {
|
||||
export function status(msg: string): void {
|
||||
if (isMacintosh) {
|
||||
alert(msg, disableRepeat); // VoiceOver does not seem to support status role
|
||||
alert(msg); // VoiceOver does not seem to support status role
|
||||
} else {
|
||||
insertMessage(statusContainer, msg, disableRepeat);
|
||||
insertMessage(statusContainer, msg);
|
||||
}
|
||||
}
|
||||
|
||||
let repeatedTimes = 0;
|
||||
let prevText: string | undefined = undefined;
|
||||
function insertMessage(target: HTMLElement, msg: string, disableRepeat?: boolean): void {
|
||||
function insertMessage(target: HTMLElement, msg: string): void {
|
||||
if (!ariaContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the same message should be inserted that is already present, a screen reader would
|
||||
// not announce this message because it matches the previous one. As a workaround, we
|
||||
// alter the message with the number of occurences unless this is explicitly disabled
|
||||
// via the disableRepeat flag.
|
||||
if (!disableRepeat) {
|
||||
if (prevText === msg) {
|
||||
repeatedTimes++;
|
||||
} else {
|
||||
prevText = msg;
|
||||
repeatedTimes = 0;
|
||||
}
|
||||
|
||||
switch (repeatedTimes) {
|
||||
case 0: break;
|
||||
case 1: msg = nls.localize('repeated', "{0} (occurred again)", msg); break;
|
||||
default: msg = nls.localize('repeatedNtimes', "{0} (occurred {1} times)", msg, repeatedTimes); break;
|
||||
}
|
||||
}
|
||||
|
||||
dom.clearNode(target);
|
||||
target.textContent = msg;
|
||||
|
||||
// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/
|
||||
target.style.visibility = 'hidden';
|
||||
target.style.visibility = 'visible';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-chevron-right {
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-breadcrumb-separator {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
import 'vs/css!./breadcrumbsWidget';
|
||||
|
||||
export abstract class BreadcrumbsItem {
|
||||
@@ -55,6 +56,8 @@ export interface IBreadcrumbsItemEvent {
|
||||
payload: any;
|
||||
}
|
||||
|
||||
const breadcrumbSeparatorIcon = registerIcon('breadcrumb-separator', Codicon.chevronRight);
|
||||
|
||||
export class BreadcrumbsWidget {
|
||||
|
||||
private readonly _disposables = new DisposableStore();
|
||||
@@ -336,7 +339,7 @@ export class BreadcrumbsWidget {
|
||||
container.tabIndex = -1;
|
||||
container.setAttribute('role', 'listitem');
|
||||
dom.addClasses(container, 'monaco-breadcrumb-item');
|
||||
const iconContainer = dom.$('.codicon.codicon-chevron-right');
|
||||
const iconContainer = dom.$(breadcrumbSeparatorIcon.cssSelector);
|
||||
container.appendChild(iconContainer);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,13 @@ import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface ICheckboxOpts extends ICheckboxStyles {
|
||||
readonly actionClassName?: string;
|
||||
readonly icon?: Codicon;
|
||||
readonly title: string;
|
||||
readonly isChecked: boolean;
|
||||
}
|
||||
@@ -93,13 +94,23 @@ export class Checkbox extends Widget {
|
||||
constructor(opts: ICheckboxOpts) {
|
||||
super();
|
||||
|
||||
this._opts = objects.deepClone(opts);
|
||||
objects.mixin(this._opts, defaultOpts, false);
|
||||
this._opts = { ...defaultOpts, ...opts };
|
||||
this._checked = this._opts.isChecked;
|
||||
|
||||
const classes = ['monaco-custom-checkbox'];
|
||||
if (this._opts.icon) {
|
||||
classes.push(this._opts.icon.classNames);
|
||||
} else {
|
||||
classes.push('codicon'); // todo@aeschli: remove once codicon fully adopted
|
||||
}
|
||||
if (this._opts.actionClassName) {
|
||||
classes.push(this._opts.actionClassName);
|
||||
}
|
||||
classes.push(this._checked ? 'checked' : 'unchecked');
|
||||
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.title = this._opts.title;
|
||||
this.domNode.className = 'monaco-custom-checkbox codicon ' + (this._opts.actionClassName || '') + ' ' + (this._checked ? 'checked' : 'unchecked');
|
||||
this.domNode.className = classes.join(' ');
|
||||
this.domNode.tabIndex = 0;
|
||||
this.domNode.setAttribute('role', 'checkbox');
|
||||
this.domNode.setAttribute('aria-checked', String(this._checked));
|
||||
@@ -192,7 +203,7 @@ export class SimpleCheckbox extends Widget {
|
||||
constructor(private title: string, private isChecked: boolean) {
|
||||
super();
|
||||
|
||||
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox codicon-check' });
|
||||
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, icon: Codicon.check, actionClassName: 'monaco-simple-checkbox' });
|
||||
|
||||
this.domNode = this.checkbox.domNode;
|
||||
|
||||
|
||||
@@ -1,427 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?a76e99e42eab7c1a55601640b708d820") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
|
||||
.codicon-add:before { content: "\ea60" }
|
||||
.codicon-plus:before { content: "\ea60" }
|
||||
.codicon-gist-new:before { content: "\ea60" }
|
||||
.codicon-repo-create:before { content: "\ea60" }
|
||||
.codicon-lightbulb:before { content: "\ea61" }
|
||||
.codicon-light-bulb:before { content: "\ea61" }
|
||||
.codicon-repo:before { content: "\ea62" }
|
||||
.codicon-repo-delete:before { content: "\ea62" }
|
||||
.codicon-gist-fork:before { content: "\ea63" }
|
||||
.codicon-repo-forked:before { content: "\ea63" }
|
||||
.codicon-git-pull-request:before { content: "\ea64" }
|
||||
.codicon-git-pull-request-abandoned:before { content: "\ea64" }
|
||||
.codicon-record-keys:before { content: "\ea65" }
|
||||
.codicon-keyboard:before { content: "\ea65" }
|
||||
.codicon-tag:before { content: "\ea66" }
|
||||
.codicon-tag-add:before { content: "\ea66" }
|
||||
.codicon-tag-remove:before { content: "\ea66" }
|
||||
.codicon-person:before { content: "\ea67" }
|
||||
.codicon-person-add:before { content: "\ea67" }
|
||||
.codicon-person-follow:before { content: "\ea67" }
|
||||
.codicon-person-outline:before { content: "\ea67" }
|
||||
.codicon-person-filled:before { content: "\ea67" }
|
||||
.codicon-git-branch:before { content: "\ea68" }
|
||||
.codicon-git-branch-create:before { content: "\ea68" }
|
||||
.codicon-git-branch-delete:before { content: "\ea68" }
|
||||
.codicon-source-control:before { content: "\ea68" }
|
||||
.codicon-mirror:before { content: "\ea69" }
|
||||
.codicon-mirror-public:before { content: "\ea69" }
|
||||
.codicon-star:before { content: "\ea6a" }
|
||||
.codicon-star-add:before { content: "\ea6a" }
|
||||
.codicon-star-delete:before { content: "\ea6a" }
|
||||
.codicon-star-empty:before { content: "\ea6a" }
|
||||
.codicon-comment:before { content: "\ea6b" }
|
||||
.codicon-comment-add:before { content: "\ea6b" }
|
||||
.codicon-alert:before { content: "\ea6c" }
|
||||
.codicon-warning:before { content: "\ea6c" }
|
||||
.codicon-search:before { content: "\ea6d" }
|
||||
.codicon-search-save:before { content: "\ea6d" }
|
||||
.codicon-log-out:before { content: "\ea6e" }
|
||||
.codicon-sign-out:before { content: "\ea6e" }
|
||||
.codicon-log-in:before { content: "\ea6f" }
|
||||
.codicon-sign-in:before { content: "\ea6f" }
|
||||
.codicon-eye:before { content: "\ea70" }
|
||||
.codicon-eye-unwatch:before { content: "\ea70" }
|
||||
.codicon-eye-watch:before { content: "\ea70" }
|
||||
.codicon-circle-filled:before { content: "\ea71" }
|
||||
.codicon-primitive-dot:before { content: "\ea71" }
|
||||
.codicon-close-dirty:before { content: "\ea71" }
|
||||
.codicon-debug-breakpoint:before { content: "\ea71" }
|
||||
.codicon-debug-breakpoint-disabled:before { content: "\ea71" }
|
||||
.codicon-debug-hint:before { content: "\ea71" }
|
||||
.codicon-primitive-square:before { content: "\ea72" }
|
||||
.codicon-edit:before { content: "\ea73" }
|
||||
.codicon-pencil:before { content: "\ea73" }
|
||||
.codicon-info:before { content: "\ea74" }
|
||||
.codicon-issue-opened:before { content: "\ea74" }
|
||||
.codicon-gist-private:before { content: "\ea75" }
|
||||
.codicon-git-fork-private:before { content: "\ea75" }
|
||||
.codicon-lock:before { content: "\ea75" }
|
||||
.codicon-mirror-private:before { content: "\ea75" }
|
||||
.codicon-close:before { content: "\ea76" }
|
||||
.codicon-remove-close:before { content: "\ea76" }
|
||||
.codicon-x:before { content: "\ea76" }
|
||||
.codicon-repo-sync:before { content: "\ea77" }
|
||||
.codicon-sync:before { content: "\ea77" }
|
||||
.codicon-clone:before { content: "\ea78" }
|
||||
.codicon-desktop-download:before { content: "\ea78" }
|
||||
.codicon-beaker:before { content: "\ea79" }
|
||||
.codicon-microscope:before { content: "\ea79" }
|
||||
.codicon-vm:before { content: "\ea7a" }
|
||||
.codicon-device-desktop:before { content: "\ea7a" }
|
||||
.codicon-file:before { content: "\ea7b" }
|
||||
.codicon-file-text:before { content: "\ea7b" }
|
||||
.codicon-more:before { content: "\ea7c" }
|
||||
.codicon-ellipsis:before { content: "\ea7c" }
|
||||
.codicon-kebab-horizontal:before { content: "\ea7c" }
|
||||
.codicon-mail-reply:before { content: "\ea7d" }
|
||||
.codicon-reply:before { content: "\ea7d" }
|
||||
.codicon-organization:before { content: "\ea7e" }
|
||||
.codicon-organization-filled:before { content: "\ea7e" }
|
||||
.codicon-organization-outline:before { content: "\ea7e" }
|
||||
.codicon-new-file:before { content: "\ea7f" }
|
||||
.codicon-file-add:before { content: "\ea7f" }
|
||||
.codicon-new-folder:before { content: "\ea80" }
|
||||
.codicon-file-directory-create:before { content: "\ea80" }
|
||||
.codicon-trash:before { content: "\ea81" }
|
||||
.codicon-trashcan:before { content: "\ea81" }
|
||||
.codicon-history:before { content: "\ea82" }
|
||||
.codicon-clock:before { content: "\ea82" }
|
||||
.codicon-folder:before { content: "\ea83" }
|
||||
.codicon-file-directory:before { content: "\ea83" }
|
||||
.codicon-symbol-folder:before { content: "\ea83" }
|
||||
.codicon-logo-github:before { content: "\ea84" }
|
||||
.codicon-mark-github:before { content: "\ea84" }
|
||||
.codicon-github:before { content: "\ea84" }
|
||||
.codicon-terminal:before { content: "\ea85" }
|
||||
.codicon-console:before { content: "\ea85" }
|
||||
.codicon-repl:before { content: "\ea85" }
|
||||
.codicon-zap:before { content: "\ea86" }
|
||||
.codicon-symbol-event:before { content: "\ea86" }
|
||||
.codicon-error:before { content: "\ea87" }
|
||||
.codicon-stop:before { content: "\ea87" }
|
||||
.codicon-variable:before { content: "\ea88" }
|
||||
.codicon-symbol-variable:before { content: "\ea88" }
|
||||
.codicon-array:before { content: "\ea8a" }
|
||||
.codicon-symbol-array:before { content: "\ea8a" }
|
||||
.codicon-symbol-module:before { content: "\ea8b" }
|
||||
.codicon-symbol-package:before { content: "\ea8b" }
|
||||
.codicon-symbol-namespace:before { content: "\ea8b" }
|
||||
.codicon-symbol-object:before { content: "\ea8b" }
|
||||
.codicon-symbol-method:before { content: "\ea8c" }
|
||||
.codicon-symbol-function:before { content: "\ea8c" }
|
||||
.codicon-symbol-constructor:before { content: "\ea8c" }
|
||||
.codicon-symbol-boolean:before { content: "\ea8f" }
|
||||
.codicon-symbol-null:before { content: "\ea8f" }
|
||||
.codicon-symbol-numeric:before { content: "\ea90" }
|
||||
.codicon-symbol-number:before { content: "\ea90" }
|
||||
.codicon-symbol-structure:before { content: "\ea91" }
|
||||
.codicon-symbol-struct:before { content: "\ea91" }
|
||||
.codicon-symbol-parameter:before { content: "\ea92" }
|
||||
.codicon-symbol-type-parameter:before { content: "\ea92" }
|
||||
.codicon-symbol-key:before { content: "\ea93" }
|
||||
.codicon-symbol-text:before { content: "\ea93" }
|
||||
.codicon-symbol-reference:before { content: "\ea94" }
|
||||
.codicon-go-to-file:before { content: "\ea94" }
|
||||
.codicon-symbol-enum:before { content: "\ea95" }
|
||||
.codicon-symbol-value:before { content: "\ea95" }
|
||||
.codicon-symbol-ruler:before { content: "\ea96" }
|
||||
.codicon-symbol-unit:before { content: "\ea96" }
|
||||
.codicon-activate-breakpoints:before { content: "\ea97" }
|
||||
.codicon-archive:before { content: "\ea98" }
|
||||
.codicon-arrow-both:before { content: "\ea99" }
|
||||
.codicon-arrow-down:before { content: "\ea9a" }
|
||||
.codicon-arrow-left:before { content: "\ea9b" }
|
||||
.codicon-arrow-right:before { content: "\ea9c" }
|
||||
.codicon-arrow-small-down:before { content: "\ea9d" }
|
||||
.codicon-arrow-small-left:before { content: "\ea9e" }
|
||||
.codicon-arrow-small-right:before { content: "\ea9f" }
|
||||
.codicon-arrow-small-up:before { content: "\eaa0" }
|
||||
.codicon-arrow-up:before { content: "\eaa1" }
|
||||
.codicon-bell:before { content: "\eaa2" }
|
||||
.codicon-bold:before { content: "\eaa3" }
|
||||
.codicon-book:before { content: "\eaa4" }
|
||||
.codicon-bookmark:before { content: "\eaa5" }
|
||||
.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" }
|
||||
.codicon-debug-breakpoint-conditional:before { content: "\eaa7" }
|
||||
.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" }
|
||||
.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" }
|
||||
.codicon-debug-breakpoint-data:before { content: "\eaa9" }
|
||||
.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" }
|
||||
.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" }
|
||||
.codicon-debug-breakpoint-log:before { content: "\eaab" }
|
||||
.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" }
|
||||
.codicon-briefcase:before { content: "\eaac" }
|
||||
.codicon-broadcast:before { content: "\eaad" }
|
||||
.codicon-browser:before { content: "\eaae" }
|
||||
.codicon-bug:before { content: "\eaaf" }
|
||||
.codicon-calendar:before { content: "\eab0" }
|
||||
.codicon-case-sensitive:before { content: "\eab1" }
|
||||
.codicon-check:before { content: "\eab2" }
|
||||
.codicon-checklist:before { content: "\eab3" }
|
||||
.codicon-chevron-down:before { content: "\eab4" }
|
||||
.codicon-chevron-left:before { content: "\eab5" }
|
||||
.codicon-chevron-right:before { content: "\eab6" }
|
||||
.codicon-chevron-up:before { content: "\eab7" }
|
||||
.codicon-chrome-close:before { content: "\eab8" }
|
||||
.codicon-chrome-maximize:before { content: "\eab9" }
|
||||
.codicon-chrome-minimize:before { content: "\eaba" }
|
||||
.codicon-chrome-restore:before { content: "\eabb" }
|
||||
.codicon-circle-outline:before { content: "\eabc" }
|
||||
.codicon-debug-breakpoint-unverified:before { content: "\eabc" }
|
||||
.codicon-circle-slash:before { content: "\eabd" }
|
||||
.codicon-circuit-board:before { content: "\eabe" }
|
||||
.codicon-clear-all:before { content: "\eabf" }
|
||||
.codicon-clippy:before { content: "\eac0" }
|
||||
.codicon-close-all:before { content: "\eac1" }
|
||||
.codicon-cloud-download:before { content: "\eac2" }
|
||||
.codicon-cloud-upload:before { content: "\eac3" }
|
||||
.codicon-code:before { content: "\eac4" }
|
||||
.codicon-collapse-all:before { content: "\eac5" }
|
||||
.codicon-color-mode:before { content: "\eac6" }
|
||||
.codicon-comment-discussion:before { content: "\eac7" }
|
||||
.codicon-compare-changes:before { content: "\eac8" }
|
||||
.codicon-credit-card:before { content: "\eac9" }
|
||||
.codicon-dash:before { content: "\eacc" }
|
||||
.codicon-dashboard:before { content: "\eacd" }
|
||||
.codicon-database:before { content: "\eace" }
|
||||
.codicon-debug-continue:before { content: "\eacf" }
|
||||
.codicon-debug-disconnect:before { content: "\ead0" }
|
||||
.codicon-debug-pause:before { content: "\ead1" }
|
||||
.codicon-debug-restart:before { content: "\ead2" }
|
||||
.codicon-debug-start:before { content: "\ead3" }
|
||||
.codicon-debug-step-into:before { content: "\ead4" }
|
||||
.codicon-debug-step-out:before { content: "\ead5" }
|
||||
.codicon-debug-step-over:before { content: "\ead6" }
|
||||
.codicon-debug-stop:before { content: "\ead7" }
|
||||
.codicon-debug:before { content: "\ead8" }
|
||||
.codicon-device-camera-video:before { content: "\ead9" }
|
||||
.codicon-device-camera:before { content: "\eada" }
|
||||
.codicon-device-mobile:before { content: "\eadb" }
|
||||
.codicon-diff-added:before { content: "\eadc" }
|
||||
.codicon-diff-ignored:before { content: "\eadd" }
|
||||
.codicon-diff-modified:before { content: "\eade" }
|
||||
.codicon-diff-removed:before { content: "\eadf" }
|
||||
.codicon-diff-renamed:before { content: "\eae0" }
|
||||
.codicon-diff:before { content: "\eae1" }
|
||||
.codicon-discard:before { content: "\eae2" }
|
||||
.codicon-editor-layout:before { content: "\eae3" }
|
||||
.codicon-empty-window:before { content: "\eae4" }
|
||||
.codicon-exclude:before { content: "\eae5" }
|
||||
.codicon-extensions:before { content: "\eae6" }
|
||||
.codicon-eye-closed:before { content: "\eae7" }
|
||||
.codicon-file-binary:before { content: "\eae8" }
|
||||
.codicon-file-code:before { content: "\eae9" }
|
||||
.codicon-file-media:before { content: "\eaea" }
|
||||
.codicon-file-pdf:before { content: "\eaeb" }
|
||||
.codicon-file-submodule:before { content: "\eaec" }
|
||||
.codicon-file-symlink-directory:before { content: "\eaed" }
|
||||
.codicon-file-symlink-file:before { content: "\eaee" }
|
||||
.codicon-file-zip:before { content: "\eaef" }
|
||||
.codicon-files:before { content: "\eaf0" }
|
||||
.codicon-filter:before { content: "\eaf1" }
|
||||
.codicon-flame:before { content: "\eaf2" }
|
||||
.codicon-fold-down:before { content: "\eaf3" }
|
||||
.codicon-fold-up:before { content: "\eaf4" }
|
||||
.codicon-fold:before { content: "\eaf5" }
|
||||
.codicon-folder-active:before { content: "\eaf6" }
|
||||
.codicon-folder-opened:before { content: "\eaf7" }
|
||||
.codicon-gear:before { content: "\eaf8" }
|
||||
.codicon-gift:before { content: "\eaf9" }
|
||||
.codicon-gist-secret:before { content: "\eafa" }
|
||||
.codicon-gist:before { content: "\eafb" }
|
||||
.codicon-git-commit:before { content: "\eafc" }
|
||||
.codicon-git-compare:before { content: "\eafd" }
|
||||
.codicon-git-merge:before { content: "\eafe" }
|
||||
.codicon-github-action:before { content: "\eaff" }
|
||||
.codicon-github-alt:before { content: "\eb00" }
|
||||
.codicon-globe:before { content: "\eb01" }
|
||||
.codicon-grabber:before { content: "\eb02" }
|
||||
.codicon-graph:before { content: "\eb03" }
|
||||
.codicon-gripper:before { content: "\eb04" }
|
||||
.codicon-heart:before { content: "\eb05" }
|
||||
.codicon-home:before { content: "\eb06" }
|
||||
.codicon-horizontal-rule:before { content: "\eb07" }
|
||||
.codicon-hubot:before { content: "\eb08" }
|
||||
.codicon-inbox:before { content: "\eb09" }
|
||||
.codicon-issue-closed:before { content: "\eb0a" }
|
||||
.codicon-issue-reopened:before { content: "\eb0b" }
|
||||
.codicon-issues:before { content: "\eb0c" }
|
||||
.codicon-italic:before { content: "\eb0d" }
|
||||
.codicon-jersey:before { content: "\eb0e" }
|
||||
.codicon-json:before { content: "\eb0f" }
|
||||
.codicon-kebab-vertical:before { content: "\eb10" }
|
||||
.codicon-key:before { content: "\eb11" }
|
||||
.codicon-law:before { content: "\eb12" }
|
||||
.codicon-lightbulb-autofix:before { content: "\eb13" }
|
||||
.codicon-link-external:before { content: "\eb14" }
|
||||
.codicon-link:before { content: "\eb15" }
|
||||
.codicon-list-ordered:before { content: "\eb16" }
|
||||
.codicon-list-unordered:before { content: "\eb17" }
|
||||
.codicon-live-share:before { content: "\eb18" }
|
||||
.codicon-loading:before { content: "\eb19" }
|
||||
.codicon-location:before { content: "\eb1a" }
|
||||
.codicon-mail-read:before { content: "\eb1b" }
|
||||
.codicon-mail:before { content: "\eb1c" }
|
||||
.codicon-markdown:before { content: "\eb1d" }
|
||||
.codicon-megaphone:before { content: "\eb1e" }
|
||||
.codicon-mention:before { content: "\eb1f" }
|
||||
.codicon-milestone:before { content: "\eb20" }
|
||||
.codicon-mortar-board:before { content: "\eb21" }
|
||||
.codicon-move:before { content: "\eb22" }
|
||||
.codicon-multiple-windows:before { content: "\eb23" }
|
||||
.codicon-mute:before { content: "\eb24" }
|
||||
.codicon-no-newline:before { content: "\eb25" }
|
||||
.codicon-note:before { content: "\eb26" }
|
||||
.codicon-octoface:before { content: "\eb27" }
|
||||
.codicon-open-preview:before { content: "\eb28" }
|
||||
.codicon-package:before { content: "\eb29" }
|
||||
.codicon-paintcan:before { content: "\eb2a" }
|
||||
.codicon-pin:before { content: "\eb2b" }
|
||||
.codicon-play:before { content: "\eb2c" }
|
||||
.codicon-run:before { content: "\eb2c" }
|
||||
.codicon-plug:before { content: "\eb2d" }
|
||||
.codicon-preserve-case:before { content: "\eb2e" }
|
||||
.codicon-preview:before { content: "\eb2f" }
|
||||
.codicon-project:before { content: "\eb30" }
|
||||
.codicon-pulse:before { content: "\eb31" }
|
||||
.codicon-question:before { content: "\eb32" }
|
||||
.codicon-quote:before { content: "\eb33" }
|
||||
.codicon-radio-tower:before { content: "\eb34" }
|
||||
.codicon-reactions:before { content: "\eb35" }
|
||||
.codicon-references:before { content: "\eb36" }
|
||||
.codicon-refresh:before { content: "\eb37" }
|
||||
.codicon-regex:before { content: "\eb38" }
|
||||
.codicon-remote-explorer:before { content: "\eb39" }
|
||||
.codicon-remote:before { content: "\eb3a" }
|
||||
.codicon-remove:before { content: "\eb3b" }
|
||||
.codicon-replace-all:before { content: "\eb3c" }
|
||||
.codicon-replace:before { content: "\eb3d" }
|
||||
.codicon-repo-clone:before { content: "\eb3e" }
|
||||
.codicon-repo-force-push:before { content: "\eb3f" }
|
||||
.codicon-repo-pull:before { content: "\eb40" }
|
||||
.codicon-repo-push:before { content: "\eb41" }
|
||||
.codicon-report:before { content: "\eb42" }
|
||||
.codicon-request-changes:before { content: "\eb43" }
|
||||
.codicon-rocket:before { content: "\eb44" }
|
||||
.codicon-root-folder-opened:before { content: "\eb45" }
|
||||
.codicon-root-folder:before { content: "\eb46" }
|
||||
.codicon-rss:before { content: "\eb47" }
|
||||
.codicon-ruby:before { content: "\eb48" }
|
||||
.codicon-save-all:before { content: "\eb49" }
|
||||
.codicon-save-as:before { content: "\eb4a" }
|
||||
.codicon-save:before { content: "\eb4b" }
|
||||
.codicon-screen-full:before { content: "\eb4c" }
|
||||
.codicon-screen-normal:before { content: "\eb4d" }
|
||||
.codicon-search-stop:before { content: "\eb4e" }
|
||||
.codicon-server:before { content: "\eb50" }
|
||||
.codicon-settings-gear:before { content: "\eb51" }
|
||||
.codicon-settings:before { content: "\eb52" }
|
||||
.codicon-shield:before { content: "\eb53" }
|
||||
.codicon-smiley:before { content: "\eb54" }
|
||||
.codicon-sort-precedence:before { content: "\eb55" }
|
||||
.codicon-split-horizontal:before { content: "\eb56" }
|
||||
.codicon-split-vertical:before { content: "\eb57" }
|
||||
.codicon-squirrel:before { content: "\eb58" }
|
||||
.codicon-star-full:before { content: "\eb59" }
|
||||
.codicon-star-half:before { content: "\eb5a" }
|
||||
.codicon-symbol-class:before { content: "\eb5b" }
|
||||
.codicon-symbol-color:before { content: "\eb5c" }
|
||||
.codicon-symbol-constant:before { content: "\eb5d" }
|
||||
.codicon-symbol-enum-member:before { content: "\eb5e" }
|
||||
.codicon-symbol-field:before { content: "\eb5f" }
|
||||
.codicon-symbol-file:before { content: "\eb60" }
|
||||
.codicon-symbol-interface:before { content: "\eb61" }
|
||||
.codicon-symbol-keyword:before { content: "\eb62" }
|
||||
.codicon-symbol-misc:before { content: "\eb63" }
|
||||
.codicon-symbol-operator:before { content: "\eb64" }
|
||||
.codicon-symbol-property:before { content: "\eb65" }
|
||||
.codicon-wrench:before { content: "\eb65" }
|
||||
.codicon-wrench-subaction:before { content: "\eb65" }
|
||||
.codicon-symbol-snippet:before { content: "\eb66" }
|
||||
.codicon-tasklist:before { content: "\eb67" }
|
||||
.codicon-telescope:before { content: "\eb68" }
|
||||
.codicon-text-size:before { content: "\eb69" }
|
||||
.codicon-three-bars:before { content: "\eb6a" }
|
||||
.codicon-thumbsdown:before { content: "\eb6b" }
|
||||
.codicon-thumbsup:before { content: "\eb6c" }
|
||||
.codicon-tools:before { content: "\eb6d" }
|
||||
.codicon-triangle-down:before { content: "\eb6e" }
|
||||
.codicon-triangle-left:before { content: "\eb6f" }
|
||||
.codicon-triangle-right:before { content: "\eb70" }
|
||||
.codicon-triangle-up:before { content: "\eb71" }
|
||||
.codicon-twitter:before { content: "\eb72" }
|
||||
.codicon-unfold:before { content: "\eb73" }
|
||||
.codicon-unlock:before { content: "\eb74" }
|
||||
.codicon-unmute:before { content: "\eb75" }
|
||||
.codicon-unverified:before { content: "\eb76" }
|
||||
.codicon-verified:before { content: "\eb77" }
|
||||
.codicon-versions:before { content: "\eb78" }
|
||||
.codicon-vm-active:before { content: "\eb79" }
|
||||
.codicon-vm-outline:before { content: "\eb7a" }
|
||||
.codicon-vm-running:before { content: "\eb7b" }
|
||||
.codicon-watch:before { content: "\eb7c" }
|
||||
.codicon-whitespace:before { content: "\eb7d" }
|
||||
.codicon-whole-word:before { content: "\eb7e" }
|
||||
.codicon-window:before { content: "\eb7f" }
|
||||
.codicon-word-wrap:before { content: "\eb80" }
|
||||
.codicon-zoom-in:before { content: "\eb81" }
|
||||
.codicon-zoom-out:before { content: "\eb82" }
|
||||
.codicon-list-filter:before { content: "\eb83" }
|
||||
.codicon-list-flat:before { content: "\eb84" }
|
||||
.codicon-list-selection:before { content: "\eb85" }
|
||||
.codicon-selection:before { content: "\eb85" }
|
||||
.codicon-list-tree:before { content: "\eb86" }
|
||||
.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" }
|
||||
.codicon-debug-breakpoint-function:before { content: "\eb88" }
|
||||
.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" }
|
||||
.codicon-debug-stackframe-active:before { content: "\eb89" }
|
||||
.codicon-debug-stackframe-dot:before { content: "\eb8a" }
|
||||
.codicon-debug-stackframe:before { content: "\eb8b" }
|
||||
.codicon-debug-stackframe-focused:before { content: "\eb8b" }
|
||||
.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" }
|
||||
.codicon-symbol-string:before { content: "\eb8d" }
|
||||
.codicon-debug-reverse-continue:before { content: "\eb8e" }
|
||||
.codicon-debug-step-back:before { content: "\eb8f" }
|
||||
.codicon-debug-restart-frame:before { content: "\eb90" }
|
||||
.codicon-debug-alternate:before { content: "\eb91" }
|
||||
.codicon-call-incoming:before { content: "\eb92" }
|
||||
.codicon-call-outgoing:before { content: "\eb93" }
|
||||
.codicon-menu:before { content: "\eb94" }
|
||||
.codicon-expand-all:before { content: "\eb95" }
|
||||
.codicon-feedback:before { content: "\eb96" }
|
||||
.codicon-group-by-ref-type:before { content: "\eb97" }
|
||||
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
|
||||
.codicon-account:before { content: "\eb99" }
|
||||
.codicon-bell-dot:before { content: "\eb9a" }
|
||||
.codicon-debug-console:before { content: "\eb9b" }
|
||||
.codicon-library:before { content: "\eb9c" }
|
||||
.codicon-output:before { content: "\eb9d" }
|
||||
.codicon-run-all:before { content: "\eb9e" }
|
||||
.codicon-sync-ignored:before { content: "\eb9f" }
|
||||
.codicon-debug-alt-2:before { content: "\f101" }
|
||||
.codicon-debug-alt:before { content: "\f102" }
|
||||
24
src/vs/base/browser/ui/codicons/codicon/codicon.css
Normal file
24
src/vs/base/browser/ui/codicons/codicon/codicon.css
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
/* icon rules are dynamically created in codiconStyles */
|
||||
Binary file not shown.
@@ -3,9 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./codicon/codicon';
|
||||
import 'vs/css!./codicon/codicon-modifications';
|
||||
import 'vs/css!./codicon/codicon-animations';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
39
src/vs/base/browser/ui/codicons/codiconStyles.ts
Normal file
39
src/vs/base/browser/ui/codicons/codiconStyles.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./codicon/codicon';
|
||||
import 'vs/css!./codicon/codicon-modifications';
|
||||
import 'vs/css!./codicon/codicon-animations';
|
||||
|
||||
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
|
||||
import { createStyleSheet } from 'vs/base/browser/dom';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
function initialize() {
|
||||
let codiconStyleSheet = createStyleSheet();
|
||||
codiconStyleSheet.id = 'codiconStyles';
|
||||
|
||||
function updateAll() {
|
||||
const rules = [];
|
||||
for (let c of iconRegistry.all) {
|
||||
rules.push(formatRule(c));
|
||||
}
|
||||
codiconStyleSheet.innerHTML = rules.join('\n');
|
||||
}
|
||||
|
||||
const delayer = new RunOnceScheduler(updateAll, 0);
|
||||
iconRegistry.onDidRegister(() => delayer.schedule());
|
||||
delayer.schedule();
|
||||
}
|
||||
|
||||
function formatRule(c: Codicon) {
|
||||
let def = c.definition;
|
||||
while (def instanceof Codicon) {
|
||||
def = def.definition;
|
||||
}
|
||||
return `.codicon-${c.id}:before { content: '${def.character}'; }`;
|
||||
}
|
||||
|
||||
initialize();
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./dialog';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { $, hide, show, EventHelper, clearNode, removeClasses, addClass, addClasses, removeNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { $, hide, show, EventHelper, clearNode, removeClasses, addClasses, removeNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
@@ -17,6 +17,7 @@ import { Action } from 'vs/base/common/actions';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { isMacintosh, isLinux } from 'vs/base/common/platform';
|
||||
import { SimpleCheckbox, ISimpleCheckboxStyles } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IDialogOptions {
|
||||
cancelId?: number;
|
||||
@@ -37,6 +38,9 @@ export interface IDialogStyles extends IButtonStyles, ISimpleCheckboxStyles {
|
||||
dialogBackground?: Color;
|
||||
dialogShadow?: Color;
|
||||
dialogBorder?: Color;
|
||||
errorIconForeground?: Color;
|
||||
warningIconForeground?: Color;
|
||||
infoIconForeground?: Color;
|
||||
}
|
||||
|
||||
interface ButtonMapEntry {
|
||||
@@ -44,6 +48,11 @@ interface ButtonMapEntry {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const dialogErrorIcon = registerIcon('dialog-error', Codicon.error);
|
||||
const dialogWarningIcon = registerIcon('dialog-warning', Codicon.warning);
|
||||
const dialogInfoIcon = registerIcon('dialog-info', Codicon.info);
|
||||
const dialogCloseIcon = registerIcon('dialog-close', Codicon.close);
|
||||
|
||||
export class Dialog extends Disposable {
|
||||
private element: HTMLElement | undefined;
|
||||
private shadowElement: HTMLElement | undefined;
|
||||
@@ -202,30 +211,29 @@ export class Dialog extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
addClass(this.iconElement, 'codicon');
|
||||
removeClasses(this.iconElement, 'codicon-alert', 'codicon-warning', 'codicon-info');
|
||||
removeClasses(this.iconElement, dialogErrorIcon.classNames, dialogWarningIcon.classNames, dialogInfoIcon.classNames, Codicon.loading.classNames);
|
||||
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
addClass(this.iconElement, 'codicon-error');
|
||||
addClasses(this.iconElement, dialogErrorIcon.classNames);
|
||||
break;
|
||||
case 'warning':
|
||||
addClass(this.iconElement, 'codicon-warning');
|
||||
addClasses(this.iconElement, dialogWarningIcon.classNames);
|
||||
break;
|
||||
case 'pending':
|
||||
addClasses(this.iconElement, 'codicon-loading', 'codicon-animation-spin');
|
||||
addClasses(this.iconElement, Codicon.loading.classNames, 'codicon-animation-spin');
|
||||
break;
|
||||
case 'none':
|
||||
case 'info':
|
||||
case 'question':
|
||||
default:
|
||||
addClass(this.iconElement, 'codicon-info');
|
||||
addClasses(this.iconElement, dialogInfoIcon.classNames);
|
||||
break;
|
||||
}
|
||||
|
||||
const actionBar = new ActionBar(this.toolbarContainer, {});
|
||||
|
||||
const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), 'codicon codicon-close', true, () => {
|
||||
const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), dialogCloseIcon.classNames, true, () => {
|
||||
resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined });
|
||||
return Promise.resolve();
|
||||
});
|
||||
@@ -268,10 +276,28 @@ export class Dialog extends Disposable {
|
||||
this.checkbox.style(style);
|
||||
}
|
||||
|
||||
if (this.messageDetailElement) {
|
||||
if (this.messageDetailElement && fgColor && bgColor) {
|
||||
const messageDetailColor = Color.fromHex(fgColor).transparent(.9);
|
||||
this.messageDetailElement.style.color = messageDetailColor.makeOpaque(Color.fromHex(bgColor)).toString();
|
||||
}
|
||||
|
||||
if (this.iconElement) {
|
||||
let color;
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
color = style.errorIconForeground;
|
||||
break;
|
||||
case 'warning':
|
||||
color = style.warningIconForeground;
|
||||
break;
|
||||
default:
|
||||
color = style.infoIconForeground;
|
||||
break;
|
||||
}
|
||||
if (color) {
|
||||
this.iconElement.style.color = color.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
const labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {
|
||||
this.element = append(el, $('a.action-label.codicon'));
|
||||
this.element = append(el, $('a.action-label.codicon')); // todo@aeschli: remove codicon, should come through `this.clazz`
|
||||
if (this.clazz) {
|
||||
addClasses(this.element, this.clazz);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IFindInputCheckboxOpts {
|
||||
readonly appendTitle: string;
|
||||
@@ -21,7 +22,7 @@ const NLS_REGEX_CHECKBOX_LABEL = nls.localize('regexDescription', "Use Regular E
|
||||
export class CaseSensitiveCheckbox extends Checkbox {
|
||||
constructor(opts: IFindInputCheckboxOpts) {
|
||||
super({
|
||||
actionClassName: 'codicon-case-sensitive',
|
||||
icon: Codicon.caseSensitive,
|
||||
title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle,
|
||||
isChecked: opts.isChecked,
|
||||
inputActiveOptionBorder: opts.inputActiveOptionBorder,
|
||||
@@ -33,7 +34,7 @@ export class CaseSensitiveCheckbox extends Checkbox {
|
||||
export class WholeWordsCheckbox extends Checkbox {
|
||||
constructor(opts: IFindInputCheckboxOpts) {
|
||||
super({
|
||||
actionClassName: 'codicon-whole-word',
|
||||
icon: Codicon.wholeWord,
|
||||
title: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle,
|
||||
isChecked: opts.isChecked,
|
||||
inputActiveOptionBorder: opts.inputActiveOptionBorder,
|
||||
@@ -45,7 +46,7 @@ export class WholeWordsCheckbox extends Checkbox {
|
||||
export class RegexCheckbox extends Checkbox {
|
||||
constructor(opts: IFindInputCheckboxOpts) {
|
||||
super({
|
||||
actionClassName: 'codicon-regex',
|
||||
icon: Codicon.regex,
|
||||
title: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle,
|
||||
isChecked: opts.isChecked,
|
||||
inputActiveOptionBorder: opts.inputActiveOptionBorder,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IReplaceInputOptions extends IReplaceInputStyles {
|
||||
readonly placeholder?: string;
|
||||
@@ -42,7 +43,7 @@ export class PreserveCaseCheckbox extends Checkbox {
|
||||
constructor(opts: IFindInputCheckboxOpts) {
|
||||
super({
|
||||
// TODO: does this need its own icon?
|
||||
actionClassName: 'codicon-preserve-case',
|
||||
icon: Codicon.preserveCase,
|
||||
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
|
||||
isChecked: opts.isChecked,
|
||||
inputActiveOptionBorder: opts.inputActiveOptionBorder,
|
||||
|
||||
@@ -594,7 +594,7 @@ export class InputBox extends Widget {
|
||||
|
||||
this.element.style.backgroundColor = background;
|
||||
this.element.style.color = foreground;
|
||||
this.input.style.backgroundColor = background;
|
||||
this.input.style.backgroundColor = 'inherit';
|
||||
this.input.style.color = foreground;
|
||||
|
||||
this.element.style.borderWidth = border ? '1px' : '';
|
||||
|
||||
@@ -129,10 +129,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-list-type-filter > .controls > .filter:checked::before {
|
||||
content: "\eb83" !important; /* codicon-list-filter */
|
||||
}
|
||||
|
||||
.monaco-list-type-filter > .controls > .filter {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
@@ -63,17 +63,6 @@ export interface IIdentityProvider<T> {
|
||||
getId(element: T): { toString(): string; };
|
||||
}
|
||||
|
||||
export enum ListAriaRootRole {
|
||||
/** default list structure role */
|
||||
LIST = 'list',
|
||||
|
||||
/** default tree structure role */
|
||||
TREE = 'tree',
|
||||
|
||||
/** role='tree' can interfere with screenreaders reading nested elements inside the tree row. Use FORM in that case. */
|
||||
FORM = 'form'
|
||||
}
|
||||
|
||||
export interface IKeyboardNavigationLabelProvider<T> {
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,10 +7,11 @@ import 'vs/css!./list';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent } from './list';
|
||||
import { List, IListStyles, IListOptions } from './listWidget';
|
||||
import { List, IListStyles, IListOptions, IListAccessibilityProvider } from './listWidget';
|
||||
import { IPagedModel } from 'vs/base/common/paging';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
|
||||
export interface IPagedRenderer<TElement, TTemplateData> extends IListRenderer<TElement, TTemplateData> {
|
||||
renderPlaceholder(index: number, templateData: TTemplateData): void;
|
||||
@@ -70,6 +71,54 @@ class PagedRenderer<TElement, TTemplateData> implements IListRenderer<number, IT
|
||||
}
|
||||
}
|
||||
|
||||
class PagedAccessibilityProvider<T> implements IListAccessibilityProvider<number> {
|
||||
|
||||
constructor(
|
||||
private modelProvider: () => IPagedModel<T>,
|
||||
private accessibilityProvider: IListAccessibilityProvider<T>
|
||||
) { }
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return this.accessibilityProvider.getWidgetAriaLabel();
|
||||
}
|
||||
|
||||
getAriaLabel(index: number): string | null {
|
||||
const model = this.modelProvider();
|
||||
|
||||
if (!model.isResolved(index)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.accessibilityProvider.getAriaLabel(model.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPagedListOptions<T> {
|
||||
readonly enableKeyboardNavigation?: boolean;
|
||||
readonly automaticKeyboardNavigation?: boolean;
|
||||
readonly ariaLabel?: string;
|
||||
readonly keyboardSupport?: boolean;
|
||||
readonly multipleSelectionSupport?: boolean;
|
||||
readonly accessibilityProvider?: IListAccessibilityProvider<T>;
|
||||
|
||||
// list view options
|
||||
readonly useShadows?: boolean;
|
||||
readonly verticalScrollMode?: ScrollbarVisibility;
|
||||
readonly setRowLineHeight?: boolean;
|
||||
readonly setRowHeight?: boolean;
|
||||
readonly supportDynamicHeights?: boolean;
|
||||
readonly mouseSupport?: boolean;
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly additionalScrollHeight?: number;
|
||||
}
|
||||
|
||||
function fromPagedListOptions<T>(modelProvider: () => IPagedModel<T>, options: IPagedListOptions<T>): IListOptions<number> {
|
||||
return {
|
||||
...options,
|
||||
accessibilityProvider: options.accessibilityProvider && new PagedAccessibilityProvider(modelProvider, options.accessibilityProvider)
|
||||
};
|
||||
}
|
||||
|
||||
export class PagedList<T> implements IDisposable {
|
||||
|
||||
private list: List<number>;
|
||||
@@ -80,10 +129,11 @@ export class PagedList<T> implements IDisposable {
|
||||
container: HTMLElement,
|
||||
virtualDelegate: IListVirtualDelegate<number>,
|
||||
renderers: IPagedRenderer<T, any>[],
|
||||
options: IListOptions<any> = {}
|
||||
options: IPagedListOptions<T> = {}
|
||||
) {
|
||||
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
|
||||
this.list = new List(user, container, virtualDelegate, pagedRenderers, options);
|
||||
const modelProvider = () => this.model;
|
||||
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, modelProvider));
|
||||
this.list = new List(user, container, virtualDelegate, pagedRenderers, fromPagedListOptions(modelProvider, options));
|
||||
}
|
||||
|
||||
getHTMLElement(): HTMLElement {
|
||||
|
||||
@@ -41,11 +41,11 @@ export interface IListViewDragAndDrop<T> extends IListDragAndDrop<T> {
|
||||
getDragElements(element: T): T[];
|
||||
}
|
||||
|
||||
export interface IAriaProvider<T> {
|
||||
getSetSize(element: T, index: number, listLength: number): number;
|
||||
getPosInSet(element: T, index: number): number;
|
||||
export interface IListViewAccessibilityProvider<T> {
|
||||
getSetSize?(element: T, index: number, listLength: number): number;
|
||||
getPosInSet?(element: T, index: number): number;
|
||||
getRole?(element: T): string;
|
||||
isChecked?(element: T): boolean;
|
||||
isChecked?(element: T): boolean | undefined;
|
||||
}
|
||||
|
||||
export interface IListViewOptions<T> {
|
||||
@@ -57,7 +57,7 @@ export interface IListViewOptions<T> {
|
||||
readonly supportDynamicHeights?: boolean;
|
||||
readonly mouseSupport?: boolean;
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly ariaProvider?: IAriaProvider<T>;
|
||||
readonly accessibilityProvider?: IListViewAccessibilityProvider<T>;
|
||||
readonly additionalScrollHeight?: number;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,40 @@ function equalsDragFeedback(f1: number[] | undefined, f2: number[] | undefined):
|
||||
return f1 === f2;
|
||||
}
|
||||
|
||||
class ListViewAccessibilityProvider<T> implements Required<IListViewAccessibilityProvider<T>> {
|
||||
|
||||
readonly getSetSize: (element: any, index: number, listLength: number) => number;
|
||||
readonly getPosInSet: (element: any, index: number) => number;
|
||||
readonly getRole: (element: T) => string;
|
||||
readonly isChecked: (element: T) => boolean | undefined;
|
||||
|
||||
constructor(accessibilityProvider?: IListViewAccessibilityProvider<T>) {
|
||||
if (accessibilityProvider?.getSetSize) {
|
||||
this.getSetSize = accessibilityProvider.getSetSize.bind(accessibilityProvider);
|
||||
} else {
|
||||
this.getSetSize = (e, i, l) => l;
|
||||
}
|
||||
|
||||
if (accessibilityProvider?.getPosInSet) {
|
||||
this.getPosInSet = accessibilityProvider.getPosInSet.bind(accessibilityProvider);
|
||||
} else {
|
||||
this.getPosInSet = (e, i) => i + 1;
|
||||
}
|
||||
|
||||
if (accessibilityProvider?.getRole) {
|
||||
this.getRole = accessibilityProvider.getRole.bind(accessibilityProvider);
|
||||
} else {
|
||||
this.getRole = _ => 'listitem';
|
||||
}
|
||||
|
||||
if (accessibilityProvider?.isChecked) {
|
||||
this.isChecked = accessibilityProvider.isChecked.bind(accessibilityProvider);
|
||||
} else {
|
||||
this.isChecked = _ => undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
private static InstanceCount = 0;
|
||||
@@ -181,7 +215,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
private supportDynamicHeights: boolean;
|
||||
private horizontalScrolling: boolean;
|
||||
private additionalScrollHeight: number;
|
||||
private ariaProvider: IAriaProvider<T>;
|
||||
private accessibilityProvider: ListViewAccessibilityProvider<T>;
|
||||
private scrollWidth: number | undefined;
|
||||
|
||||
private dnd: IListViewDragAndDrop<T>;
|
||||
@@ -237,7 +271,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
this.additionalScrollHeight = typeof options.additionalScrollHeight === 'undefined' ? 0 : options.additionalScrollHeight;
|
||||
|
||||
this.ariaProvider = options.ariaProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 };
|
||||
this.accessibilityProvider = new ListViewAccessibilityProvider(options.accessibilityProvider);
|
||||
|
||||
this.rowsContainer = document.createElement('div');
|
||||
this.rowsContainer.className = 'monaco-list-rows';
|
||||
@@ -611,11 +645,11 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
if (!item.row) {
|
||||
item.row = this.cache.alloc(item.templateId);
|
||||
const role = this.ariaProvider.getRole ? this.ariaProvider.getRole(item.element) : 'listitem';
|
||||
const role = this.accessibilityProvider.getRole(item.element);
|
||||
item.row!.domNode!.setAttribute('role', role);
|
||||
const checked = this.ariaProvider.isChecked ? this.ariaProvider.isChecked(item.element) : undefined;
|
||||
const checked = this.accessibilityProvider.isChecked(item.element);
|
||||
if (typeof checked !== 'undefined') {
|
||||
item.row!.domNode!.setAttribute('aria-checked', String(checked));
|
||||
item.row!.domNode!.setAttribute('aria-checked', String(!!checked));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,8 +721,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
item.row!.domNode!.setAttribute('data-index', `${index}`);
|
||||
item.row!.domNode!.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false');
|
||||
item.row!.domNode!.setAttribute('aria-setsize', String(this.ariaProvider.getSetSize(item.element, index, this.length)));
|
||||
item.row!.domNode!.setAttribute('aria-posinset', String(this.ariaProvider.getPosInSet(item.element, index)));
|
||||
item.row!.domNode!.setAttribute('aria-setsize', String(this.accessibilityProvider.getSetSize(item.element, index, this.length)));
|
||||
item.row!.domNode!.setAttribute('aria-posinset', String(this.accessibilityProvider.getPosInSet(item.element, index)));
|
||||
item.row!.domNode!.setAttribute('id', this.getElementDomId(index));
|
||||
|
||||
DOM.toggleClass(item.row!.domNode!, 'drop-target', item.dropTarget);
|
||||
|
||||
@@ -16,8 +16,8 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Event, Emitter, EventBufferer } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole, ListError, IKeyboardNavigationDelegate } from './list';
|
||||
import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaProvider } from './listView';
|
||||
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';
|
||||
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider } from './listView';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
|
||||
@@ -686,25 +686,11 @@ export interface IStyleController {
|
||||
style(styles: IListStyles): void;
|
||||
}
|
||||
|
||||
export interface IAccessibilityProvider<T> {
|
||||
|
||||
/**
|
||||
* Given an element in the tree, return the ARIA label that should be associated with the
|
||||
* item. This helps screen readers to provide a meaningful label for the currently focused
|
||||
* tree element.
|
||||
*
|
||||
* Returning null will not disable ARIA for the element. Instead it is up to the screen reader
|
||||
* to compute a meaningful label based on the contents of the element in the DOM
|
||||
*
|
||||
* See also: https://www.w3.org/TR/wai-aria/#aria-label
|
||||
*/
|
||||
export interface IListAccessibilityProvider<T> extends IListViewAccessibilityProvider<T> {
|
||||
getAriaLabel(element: T): string | null;
|
||||
|
||||
/**
|
||||
* https://www.w3.org/TR/wai-aria/#aria-level
|
||||
*/
|
||||
getWidgetAriaLabel(): string;
|
||||
getWidgetRole?(): string;
|
||||
getAriaLevel?(element: T): number | undefined;
|
||||
|
||||
onDidChangeActiveDescendant?: Event<void>;
|
||||
getActiveDescendantId?(element: T): string | undefined;
|
||||
}
|
||||
@@ -836,14 +822,12 @@ export interface IListOptions<T> {
|
||||
readonly automaticKeyboardNavigation?: boolean;
|
||||
readonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider<T>;
|
||||
readonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate;
|
||||
readonly ariaRole?: ListAriaRootRole | string;
|
||||
readonly ariaLabel?: string;
|
||||
readonly keyboardSupport?: boolean;
|
||||
readonly multipleSelectionSupport?: boolean;
|
||||
readonly multipleSelectionController?: IMultipleSelectionController<T>;
|
||||
readonly openController?: IOpenController;
|
||||
readonly styleController?: (suffix: string) => IStyleController;
|
||||
readonly accessibilityProvider?: IAccessibilityProvider<T>;
|
||||
readonly accessibilityProvider?: IListAccessibilityProvider<T>;
|
||||
|
||||
// list view options
|
||||
readonly useShadows?: boolean;
|
||||
@@ -853,7 +837,6 @@ export interface IListOptions<T> {
|
||||
readonly supportDynamicHeights?: boolean;
|
||||
readonly mouseSupport?: boolean;
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly ariaProvider?: IAriaProvider<T>;
|
||||
readonly additionalScrollHeight?: number;
|
||||
}
|
||||
|
||||
@@ -894,7 +877,7 @@ const defaultStyles: IListStyles = {
|
||||
treeIndentGuidesStroke: Color.fromHex('#a9a9a9')
|
||||
};
|
||||
|
||||
const DefaultOptions = {
|
||||
const DefaultOptions: IListOptions<any> = {
|
||||
keyboardSupport: true,
|
||||
mouseSupport: true,
|
||||
multipleSelectionSupport: true,
|
||||
@@ -903,8 +886,7 @@ const DefaultOptions = {
|
||||
onDragStart(): void { },
|
||||
onDragOver() { return false; },
|
||||
drop() { }
|
||||
},
|
||||
ariaRootRole: ListAriaRootRole.LIST
|
||||
}
|
||||
};
|
||||
|
||||
// TODO@Joao: move these utils into a SortedArray class
|
||||
@@ -1036,7 +1018,7 @@ class AccessibiltyRenderer<T> implements IListRenderer<T, HTMLElement> {
|
||||
|
||||
templateId: string = 'a18n';
|
||||
|
||||
constructor(private accessibilityProvider: IAccessibilityProvider<T>) { }
|
||||
constructor(private accessibilityProvider: IListAccessibilityProvider<T>) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
@@ -1123,7 +1105,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
private spliceable: ISpliceable<T>;
|
||||
private styleController: IStyleController;
|
||||
private typeLabelController?: TypeLabelController<T>;
|
||||
private accessibilityProvider?: IAccessibilityProvider<T>;
|
||||
private accessibilityProvider?: IListAccessibilityProvider<T>;
|
||||
private _ariaLabel: string = '';
|
||||
|
||||
protected readonly disposables = new DisposableStore();
|
||||
|
||||
@@ -1202,7 +1185,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
renderers: IListRenderer<any /* TODO@joao */, any>[],
|
||||
private _options: IListOptions<T> = DefaultOptions
|
||||
) {
|
||||
this.selection = new SelectionTrait(this._options.ariaRole !== 'listbox');
|
||||
const role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';
|
||||
this.selection = new SelectionTrait(role !== 'listbox');
|
||||
this.focus = new Trait('focused');
|
||||
|
||||
mixin(_options, defaultStyles, false);
|
||||
@@ -1227,12 +1211,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
};
|
||||
|
||||
this.view = new ListView(container, virtualDelegate, renderers, viewOptions);
|
||||
|
||||
if (typeof _options.ariaRole !== 'string') {
|
||||
this.view.domNode.setAttribute('role', ListAriaRootRole.LIST);
|
||||
} else {
|
||||
this.view.domNode.setAttribute('role', _options.ariaRole);
|
||||
}
|
||||
this.view.domNode.setAttribute('role', role);
|
||||
|
||||
if (_options.styleController) {
|
||||
this.styleController = _options.styleController(this.view.domId);
|
||||
@@ -1273,8 +1252,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
this.onDidChangeFocus(this._onFocusChange, this, this.disposables);
|
||||
this.onDidChangeSelection(this._onSelectionChange, this, this.disposables);
|
||||
|
||||
if (_options.ariaLabel) {
|
||||
this.view.domNode.setAttribute('aria-label', localize('aria list', "{0}. Use the navigation keys to navigate.", _options.ariaLabel));
|
||||
if (this.accessibilityProvider) {
|
||||
this.ariaLabel = this.accessibilityProvider.getWidgetAriaLabel();
|
||||
}
|
||||
if (_options.multipleSelectionSupport) {
|
||||
this.view.domNode.setAttribute('aria-multiselectable', 'true');
|
||||
@@ -1377,6 +1356,15 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
return this.view.lastVisibleIndex;
|
||||
}
|
||||
|
||||
get ariaLabel(): string {
|
||||
return this._ariaLabel;
|
||||
}
|
||||
|
||||
set ariaLabel(value: string) {
|
||||
this._ariaLabel = value;
|
||||
this.view.domNode.setAttribute('aria-label', localize('aria list', "{0}. Use the navigation keys to navigate.", value));
|
||||
}
|
||||
|
||||
domFocus(): void {
|
||||
this.view.domNode.focus();
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
|
||||
.menubar.compact {
|
||||
flex-shrink: 0;
|
||||
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
|
||||
}
|
||||
|
||||
.menubar.compact > .menubar-menu-button {
|
||||
@@ -201,7 +202,7 @@
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more {
|
||||
position: absolute;
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 5.625H0V4.5H18V5.625ZM18 14.625H0V13.5H18V14.625ZM18 10.1162H0V9H18V10.1162Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 209 B |
@@ -19,11 +19,14 @@ import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { stripCodicons } from 'vs/base/common/codicons';
|
||||
import { Codicon, registerIcon, stripCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\s&])/g;
|
||||
|
||||
const menuSelectionIcon = registerIcon('menu-selection', Codicon.check);
|
||||
const menuSubmenuIcon = registerIcon('menu-submenu', Codicon.chevronRight);
|
||||
|
||||
export enum Direction {
|
||||
Right,
|
||||
Left
|
||||
@@ -423,7 +426,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
this.check = append(this.item, $('span.menu-item-check.codicon.codicon-check'));
|
||||
this.check = append(this.item, $('span.menu-item-check' + menuSelectionIcon.cssSelector));
|
||||
this.check.setAttribute('role', 'none');
|
||||
|
||||
this.label = append(this.item, $('span.action-label'));
|
||||
@@ -670,7 +673,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
|
||||
addClass(this.item, 'monaco-submenu-item');
|
||||
this.item.setAttribute('aria-haspopup', 'true');
|
||||
this.updateAriaExpanded('false');
|
||||
this.submenuIndicator = append(this.item, $('span.submenu-indicator.codicon.codicon-chevron-right'));
|
||||
this.submenuIndicator = append(this.item, $('span.submenu-indicator' + menuSubmenuIcon.cssSelector));
|
||||
this.submenuIndicator.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,12 @@ import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
const menuBarMoreIcon = registerIcon('menubar-more', Codicon.more);
|
||||
|
||||
export interface IMenuBarOptions {
|
||||
enableMnemonics?: boolean;
|
||||
disableAltFocus?: boolean;
|
||||
@@ -313,7 +316,7 @@ export class MenuBar extends Disposable {
|
||||
const label = this.options.compactMode !== undefined ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', 'More');
|
||||
const title = this.options.compactMode !== undefined ? label : undefined;
|
||||
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'title': title, 'aria-haspopup': true });
|
||||
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more.codicon.codicon-more', { 'role': 'none', 'aria-hidden': true });
|
||||
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more' + menuBarMoreIcon.cssSelector, { 'role': 'none', 'aria-hidden': true });
|
||||
|
||||
buttonElement.appendChild(titleElement);
|
||||
this.container.appendChild(buttonElement);
|
||||
|
||||
@@ -9,6 +9,11 @@ import { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/s
|
||||
import { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
|
||||
const scrollbarButtonLeftIcon = registerIcon('scrollbar-button-left', Codicon.triangleLeft);
|
||||
const scrollbarButtonRightIcon = registerIcon('scrollbar-button-right', Codicon.triangleRight);
|
||||
|
||||
export class HorizontalScrollbar extends AbstractScrollbar {
|
||||
|
||||
@@ -36,7 +41,8 @@ export class HorizontalScrollbar extends AbstractScrollbar {
|
||||
let scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;
|
||||
|
||||
this._createArrow({
|
||||
className: 'scra codicon codicon-triangle-left',
|
||||
className: 'scra',
|
||||
icon: scrollbarButtonLeftIcon,
|
||||
top: scrollbarDelta,
|
||||
left: arrowDelta,
|
||||
bottom: undefined,
|
||||
@@ -47,7 +53,8 @@ export class HorizontalScrollbar extends AbstractScrollbar {
|
||||
});
|
||||
|
||||
this._createArrow({
|
||||
className: 'scra codicon codicon-triangle-right',
|
||||
className: 'scra',
|
||||
icon: scrollbarButtonRightIcon,
|
||||
top: scrollbarDelta,
|
||||
left: undefined,
|
||||
bottom: undefined,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/scrollbars';
|
||||
import { isEdge } from 'vs/base/browser/browser';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||
@@ -266,7 +265,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
}
|
||||
|
||||
public setScrollDimensions(dimensions: INewScrollDimensions): void {
|
||||
this._scrollable.setScrollDimensions(dimensions);
|
||||
this._scrollable.setScrollDimensions(dimensions, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,7 +335,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
this._onMouseWheel(new StandardWheelEvent(browserEvent));
|
||||
};
|
||||
|
||||
this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { passive: false }));
|
||||
this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveM
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { addClasses } from 'vs/base/browser/dom';
|
||||
|
||||
/**
|
||||
* The arrow image size.
|
||||
@@ -16,6 +18,7 @@ export const ARROW_IMG_SIZE = 11;
|
||||
export interface ScrollbarArrowOptions {
|
||||
onActivate: () => void;
|
||||
className: string;
|
||||
icon: Codicon;
|
||||
|
||||
bgWidth: number;
|
||||
bgHeight: number;
|
||||
@@ -59,6 +62,8 @@ export class ScrollbarArrow extends Widget {
|
||||
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.className = opts.className;
|
||||
addClasses(this.domNode, opts.icon.classNames);
|
||||
|
||||
this.domNode.style.position = 'absolute';
|
||||
this.domNode.style.width = ARROW_IMG_SIZE + 'px';
|
||||
this.domNode.style.height = ARROW_IMG_SIZE + 'px';
|
||||
|
||||
@@ -9,6 +9,10 @@ import { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/s
|
||||
import { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const scrollbarButtonUpIcon = registerIcon('scrollbar-button-up', Codicon.triangleUp);
|
||||
const scrollbarButtonDownIcon = registerIcon('scrollbar-button-down', Codicon.triangleDown);
|
||||
|
||||
export class VerticalScrollbar extends AbstractScrollbar {
|
||||
|
||||
@@ -37,7 +41,8 @@ export class VerticalScrollbar extends AbstractScrollbar {
|
||||
let scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;
|
||||
|
||||
this._createArrow({
|
||||
className: 'scra codicon codicon-triangle-up',
|
||||
className: 'scra',
|
||||
icon: scrollbarButtonUpIcon,
|
||||
top: arrowDelta,
|
||||
left: scrollbarDelta,
|
||||
bottom: undefined,
|
||||
@@ -48,7 +53,8 @@ export class VerticalScrollbar extends AbstractScrollbar {
|
||||
});
|
||||
|
||||
this._createArrow({
|
||||
className: 'scra codicon codicon-triangle-down',
|
||||
className: 'scra',
|
||||
icon: scrollbarButtonDownIcon,
|
||||
top: undefined,
|
||||
left: scrollbarDelta,
|
||||
bottom: arrowDelta,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxSty
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -732,12 +733,20 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
||||
this.listRenderer = new SelectListRenderer();
|
||||
|
||||
this.selectList = new List('SelectBoxCustom', this.selectDropDownListContainer, this, [this.listRenderer], {
|
||||
ariaLabel: this.selectBoxOptions.ariaLabel,
|
||||
useShadows: false,
|
||||
verticalScrollMode: ScrollbarVisibility.Visible,
|
||||
keyboardSupport: false,
|
||||
mouseSupport: false
|
||||
mouseSupport: false,
|
||||
accessibilityProvider: {
|
||||
getAriaLabel: (element) => element.text,
|
||||
getWidgetAriaLabel: () => localize('selectBox', "Select Box"),
|
||||
getRole: () => 'option',
|
||||
getWidgetRole: () => 'listbox'
|
||||
}
|
||||
});
|
||||
if (this.selectBoxOptions.ariaLabel) {
|
||||
this.selectList.ariaLabel = this.selectBoxOptions.ariaLabel;
|
||||
}
|
||||
|
||||
// SetUp list keyboard controller - control navigation, disabled items, focus
|
||||
const onSelectDropDownKeyDown = Event.chain(domEvent(this.selectDropDownListContainer, 'keydown'))
|
||||
|
||||
@@ -236,6 +236,7 @@ export abstract class Pane extends Disposable implements IView {
|
||||
const height = this._orientation === Orientation.VERTICAL ? size - headerSize : this.orthogonalSize - headerSize;
|
||||
|
||||
if (this.isExpanded()) {
|
||||
toggleClass(this.body, 'wide', width >= 600);
|
||||
this.layoutBody(height, width);
|
||||
this.expandedSize = size;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,12 @@ import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
export const CONTEXT = 'context.toolbar';
|
||||
|
||||
const toolBarMoreIcon = registerIcon('toolbar-more', Codicon.more);
|
||||
|
||||
export interface IToolBarOptions {
|
||||
orientation?: ActionsOrientation;
|
||||
actionViewItemProvider?: IActionViewItemProvider;
|
||||
@@ -65,7 +68,7 @@ export class ToolBar extends Disposable {
|
||||
this.options.actionViewItemProvider,
|
||||
this.actionRunner,
|
||||
this.options.getKeyBinding,
|
||||
'codicon-more',
|
||||
toolBarMoreIcon.classNames,
|
||||
this.options.anchorAlignmentProvider
|
||||
);
|
||||
this.toggleMenuActionViewItem.value.setActionContext(this.actionBar.context);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/tree';
|
||||
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate, ListAriaRootRole } from 'vs/base/browser/ui/list/list';
|
||||
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode, addClasses, removeClasses } from 'vs/base/browser/dom';
|
||||
import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
@@ -26,6 +26,7 @@ import { values } from 'vs/base/common/map';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { ScrollEvent } from 'vs/base/common/scrollable';
|
||||
import { SetMap } from 'vs/base/common/collections';
|
||||
import { treeItemExpandedIcon, treeFilterOnTypeOnIcon, treeFilterOnTypeOffIcon, treeFilterClearIcon } from 'vs/base/browser/ui/tree/treeIcons';
|
||||
|
||||
class TreeElementsDragAndDropData<T, TFilterData, TContext> extends ElementsDragAndDropData<T, TContext> {
|
||||
|
||||
@@ -162,9 +163,30 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
|
||||
},
|
||||
accessibilityProvider: options.accessibilityProvider && {
|
||||
...options.accessibilityProvider,
|
||||
getSetSize(node) {
|
||||
const model = modelProvider();
|
||||
const ref = model.getNodeLocation(node);
|
||||
const parentRef = model.getParentNodeLocation(ref);
|
||||
const parentNode = model.getNode(parentRef);
|
||||
|
||||
return parentNode.visibleChildrenCount;
|
||||
},
|
||||
getPosInSet(node) {
|
||||
return node.visibleChildIndex + 1;
|
||||
},
|
||||
isChecked: options.accessibilityProvider && options.accessibilityProvider.isChecked ? (node) => {
|
||||
return options.accessibilityProvider!.isChecked!(node.element);
|
||||
} : undefined,
|
||||
getRole: options.accessibilityProvider && options.accessibilityProvider.getRole ? (node) => {
|
||||
return options.accessibilityProvider!.getRole!(node.element);
|
||||
} : () => 'treeitem',
|
||||
getAriaLabel(e) {
|
||||
return options.accessibilityProvider!.getAriaLabel(e.element);
|
||||
},
|
||||
getWidgetAriaLabel() {
|
||||
return options.accessibilityProvider!.getWidgetAriaLabel();
|
||||
},
|
||||
getWidgetRole: options.accessibilityProvider && options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',
|
||||
getAriaLevel(node) {
|
||||
return node.depth;
|
||||
},
|
||||
@@ -178,27 +200,7 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
|
||||
return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(node.element);
|
||||
}
|
||||
},
|
||||
enableKeyboardNavigation: options.simpleKeyboardNavigation,
|
||||
ariaProvider: {
|
||||
getSetSize(node) {
|
||||
const model = modelProvider();
|
||||
const ref = model.getNodeLocation(node);
|
||||
const parentRef = model.getParentNodeLocation(ref);
|
||||
const parentNode = model.getNode(parentRef);
|
||||
|
||||
return parentNode.visibleChildrenCount;
|
||||
},
|
||||
getPosInSet(node) {
|
||||
return node.visibleChildIndex + 1;
|
||||
},
|
||||
isChecked: options.ariaProvider && options.ariaProvider.isChecked ? (node) => {
|
||||
return options.ariaProvider!.isChecked!(node.element);
|
||||
} : undefined,
|
||||
getRole: options.ariaProvider && options.ariaProvider.getRole ? (node) => {
|
||||
return options.ariaProvider!.getRole!(node.element);
|
||||
} : () => 'treeitem'
|
||||
},
|
||||
ariaRole: ListAriaRootRole.TREE
|
||||
enableKeyboardNavigation: options.simpleKeyboardNavigation
|
||||
};
|
||||
}
|
||||
|
||||
@@ -404,10 +406,10 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
|
||||
}
|
||||
|
||||
if (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) {
|
||||
addClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible');
|
||||
addClasses(templateData.twistie, treeItemExpandedIcon.classNames, 'collapsible');
|
||||
toggleClass(templateData.twistie, 'collapsed', node.collapsed);
|
||||
} else {
|
||||
removeClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible', 'collapsed');
|
||||
removeClasses(templateData.twistie, treeItemExpandedIcon.classNames, 'collapsible', 'collapsed');
|
||||
}
|
||||
|
||||
if (node.collapsible) {
|
||||
@@ -645,14 +647,14 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
const controls = append(this.domNode, $('.controls'));
|
||||
|
||||
this._filterOnType = !!tree.options.filterOnType;
|
||||
this.filterOnTypeDomNode = append(controls, $<HTMLInputElement>('input.filter.codicon.codicon-list-selection'));
|
||||
this.filterOnTypeDomNode = append(controls, $<HTMLInputElement>('input.filter'));
|
||||
this.filterOnTypeDomNode.type = 'checkbox';
|
||||
this.filterOnTypeDomNode.checked = this._filterOnType;
|
||||
this.filterOnTypeDomNode.tabIndex = -1;
|
||||
this.updateFilterOnTypeTitle();
|
||||
this.updateFilterOnTypeTitleAndIcon();
|
||||
domEvent(this.filterOnTypeDomNode, 'input')(this.onDidChangeFilterOnType, this, this.disposables);
|
||||
|
||||
this.clearDomNode = append(controls, $<HTMLInputElement>('button.clear.codicon.codicon-close'));
|
||||
this.clearDomNode = append(controls, $<HTMLInputElement>('button.clear' + treeFilterClearIcon.cssSelector));
|
||||
this.clearDomNode.tabIndex = -1;
|
||||
this.clearDomNode.title = localize('clear', "Clear");
|
||||
|
||||
@@ -858,13 +860,17 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
|
||||
this.tree.refilter();
|
||||
this.tree.domFocus();
|
||||
this.render();
|
||||
this.updateFilterOnTypeTitle();
|
||||
this.updateFilterOnTypeTitleAndIcon();
|
||||
}
|
||||
|
||||
private updateFilterOnTypeTitle(): void {
|
||||
private updateFilterOnTypeTitleAndIcon(): void {
|
||||
if (this.filterOnType) {
|
||||
removeClasses(this.filterOnTypeDomNode, treeFilterOnTypeOffIcon.classNames);
|
||||
addClasses(this.filterOnTypeDomNode, treeFilterOnTypeOnIcon.classNames);
|
||||
this.filterOnTypeDomNode.title = localize('disable filter on type', "Disable Filter on Type");
|
||||
} else {
|
||||
removeClasses(this.filterOnTypeDomNode, treeFilterOnTypeOnIcon.classNames);
|
||||
addClasses(this.filterOnTypeDomNode, treeFilterOnTypeOffIcon.classNames);
|
||||
this.filterOnTypeDomNode.title = localize('enable filter on type', "Enable Filter on Type");
|
||||
}
|
||||
}
|
||||
@@ -1445,6 +1451,14 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
return node.element;
|
||||
}
|
||||
|
||||
get ariaLabel(): string {
|
||||
return this.view.ariaLabel;
|
||||
}
|
||||
|
||||
set ariaLabel(value: string) {
|
||||
this.view.ariaLabel = value;
|
||||
}
|
||||
|
||||
domFocus(): void {
|
||||
this.view.domFocus();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole } from 'vs/base/browser/ui/list/list';
|
||||
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper, ITreeFilter, TreeVisibility, TreeFilterResult } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -15,12 +15,13 @@ import { Iterable } from 'vs/base/common/iterator';
|
||||
import { IDragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { toggleClass } from 'vs/base/browser/dom';
|
||||
import { removeClasses, addClasses } from 'vs/base/browser/dom';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { ScrollEvent } from 'vs/base/common/scrollable';
|
||||
import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { IThemable } from 'vs/base/common/styler';
|
||||
import { isFilterResult, getVisibleState } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
import { treeItemLoadingIcon } from 'vs/base/browser/ui/tree/treeIcons';
|
||||
|
||||
interface IAsyncDataTreeNode<TInput, T> {
|
||||
element: TInput | T;
|
||||
@@ -109,7 +110,11 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
|
||||
}
|
||||
|
||||
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
|
||||
toggleClass(twistieElement, 'codicon-loading', element.slow);
|
||||
if (element.slow) {
|
||||
addClasses(twistieElement, treeItemLoadingIcon.classNames);
|
||||
} else {
|
||||
removeClasses(twistieElement, treeItemLoadingIcon.classNames);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -231,9 +236,21 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
|
||||
},
|
||||
accessibilityProvider: options.accessibilityProvider && {
|
||||
...options.accessibilityProvider,
|
||||
getPosInSet: undefined,
|
||||
getSetSize: undefined,
|
||||
getRole: options.accessibilityProvider!.getRole ? (el) => {
|
||||
return options.accessibilityProvider!.getRole!(el.element as T);
|
||||
} : () => 'treeitem',
|
||||
isChecked: options.accessibilityProvider!.isChecked ? (e) => {
|
||||
return !!(options.accessibilityProvider?.isChecked!(e.element as T));
|
||||
} : undefined,
|
||||
getAriaLabel(e) {
|
||||
return options.accessibilityProvider!.getAriaLabel(e.element as T);
|
||||
},
|
||||
getWidgetAriaLabel() {
|
||||
return options.accessibilityProvider!.getWidgetAriaLabel();
|
||||
},
|
||||
getWidgetRole: options.accessibilityProvider!.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',
|
||||
getAriaLevel: options.accessibilityProvider!.getAriaLevel && (node => {
|
||||
return options.accessibilityProvider!.getAriaLevel!(node.element as T);
|
||||
}),
|
||||
@@ -258,21 +275,6 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
|
||||
e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T)
|
||||
)
|
||||
),
|
||||
ariaProvider: options.ariaProvider && {
|
||||
getPosInSet(el, index) {
|
||||
return options.ariaProvider!.getPosInSet(el.element as T, index);
|
||||
},
|
||||
getSetSize(el, index, listLength) {
|
||||
return options.ariaProvider!.getSetSize(el.element as T, index, listLength);
|
||||
},
|
||||
getRole: options.ariaProvider!.getRole ? (el) => {
|
||||
return options.ariaProvider!.getRole!(el.element as T);
|
||||
} : () => 'treeitem',
|
||||
isChecked: options.ariaProvider!.isChecked ? (e) => {
|
||||
return !!(options.ariaProvider?.isChecked!(e.element as T));
|
||||
} : undefined
|
||||
},
|
||||
ariaRole: ListAriaRootRole.TREE,
|
||||
additionalScrollHeight: options.additionalScrollHeight
|
||||
};
|
||||
}
|
||||
@@ -448,6 +450,14 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
||||
return this.tree.lastVisibleElement!.element as T;
|
||||
}
|
||||
|
||||
get ariaLabel(): string {
|
||||
return this.tree.ariaLabel;
|
||||
}
|
||||
|
||||
set ariaLabel(value: string) {
|
||||
this.tree.ariaLabel = value;
|
||||
}
|
||||
|
||||
domFocus(): void {
|
||||
this.tree.domFocus();
|
||||
}
|
||||
@@ -1044,7 +1054,11 @@ class CompressibleAsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> i
|
||||
}
|
||||
|
||||
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
|
||||
toggleClass(twistieElement, 'codicon-loading', element.slow);
|
||||
if (element.slow) {
|
||||
addClasses(twistieElement, treeItemLoadingIcon.classNames);
|
||||
} else {
|
||||
removeClasses(twistieElement, treeItemLoadingIcon.classNames);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,6 @@
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.monaco-tl-twistie.codicon-loading::before {
|
||||
.monaco-tl-twistie.codicon-tree-item-loading::before {
|
||||
animation: codicon-spin 1.25s linear infinite;
|
||||
}
|
||||
|
||||
14
src/vs/base/browser/ui/tree/treeIcons.ts
Normal file
14
src/vs/base/browser/ui/tree/treeIcons.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
export const treeItemExpandedIcon = registerIcon('tree-item-expanded', Codicon.chevronDown); // collapsed is done with rotation
|
||||
|
||||
export const treeFilterOnTypeOnIcon = registerIcon('tree-filter-on-type-on', Codicon.listFilter);
|
||||
export const treeFilterOnTypeOffIcon = registerIcon('tree-filter-on-type-off', Codicon.listSelection);
|
||||
export const treeFilterClearIcon = registerIcon('tree-filter-clear', Codicon.close);
|
||||
|
||||
export const treeItemLoadingIcon = registerIcon('tree-item-loading', Codicon.loading);
|
||||
@@ -4,6 +4,473 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { codiconStartMarker } from 'vs/base/common/codicon';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export interface IIconRegistry {
|
||||
readonly all: IterableIterator<Codicon>;
|
||||
readonly onDidRegister: Event<Codicon>;
|
||||
get(id: string): Codicon | undefined;
|
||||
}
|
||||
|
||||
class Registry implements IIconRegistry {
|
||||
|
||||
private readonly _icons = new Map<string, Codicon>();
|
||||
private readonly _onDidRegister = new Emitter<Codicon>();
|
||||
|
||||
public add(icon: Codicon) {
|
||||
if (!this._icons.has(icon.id)) {
|
||||
this._icons.set(icon.id, icon);
|
||||
this._onDidRegister.fire(icon);
|
||||
} else {
|
||||
console.error(`Duplicate registration of codicon ${icon.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
public get(id: string): Codicon | undefined {
|
||||
return this._icons.get(id);
|
||||
}
|
||||
|
||||
public get all(): IterableIterator<Codicon> {
|
||||
return this._icons.values();
|
||||
}
|
||||
|
||||
public get onDidRegister(): Event<Codicon> {
|
||||
return this._onDidRegister.event;
|
||||
}
|
||||
}
|
||||
|
||||
const _registry = new Registry();
|
||||
|
||||
export const iconRegistry: IIconRegistry = _registry;
|
||||
|
||||
export function registerIcon(id: string, def: Codicon) {
|
||||
return new Codicon(id, def);
|
||||
}
|
||||
|
||||
export class Codicon {
|
||||
constructor(public readonly id: string, public readonly definition: Codicon | IconDefinition) {
|
||||
_registry.add(this);
|
||||
}
|
||||
public get classNames() { return 'codicon codicon-' + this.id; }
|
||||
public get cssSelector() { return '.codicon.codicon-' + this.id; }
|
||||
}
|
||||
|
||||
interface IconDefinition {
|
||||
character: string;
|
||||
}
|
||||
|
||||
export namespace Codicon {
|
||||
|
||||
// built-in icons, with image name
|
||||
export const add = new Codicon('add', { character: '\\ea60' });
|
||||
export const plus = new Codicon('plus', { character: '\\ea60' });
|
||||
export const gistNew = new Codicon('gist-new', { character: '\\ea60' });
|
||||
export const repoCreate = new Codicon('repo-create', { character: '\\ea60' });
|
||||
export const lightbulb = new Codicon('lightbulb', { character: '\\ea61' });
|
||||
export const lightBulb = new Codicon('light-bulb', { character: '\\ea61' });
|
||||
export const repo = new Codicon('repo', { character: '\\ea62' });
|
||||
export const repoDelete = new Codicon('repo-delete', { character: '\\ea62' });
|
||||
export const gistFork = new Codicon('gist-fork', { character: '\\ea63' });
|
||||
export const repoForked = new Codicon('repo-forked', { character: '\\ea63' });
|
||||
export const gitPullRequest = new Codicon('git-pull-request', { character: '\\ea64' });
|
||||
export const gitPullRequestAbandoned = new Codicon('git-pull-request-abandoned', { character: '\\ea64' });
|
||||
export const recordKeys = new Codicon('record-keys', { character: '\\ea65' });
|
||||
export const keyboard = new Codicon('keyboard', { character: '\\ea65' });
|
||||
export const tag = new Codicon('tag', { character: '\\ea66' });
|
||||
export const tagAdd = new Codicon('tag-add', { character: '\\ea66' });
|
||||
export const tagRemove = new Codicon('tag-remove', { character: '\\ea66' });
|
||||
export const person = new Codicon('person', { character: '\\ea67' });
|
||||
export const personAdd = new Codicon('person-add', { character: '\\ea67' });
|
||||
export const personFollow = new Codicon('person-follow', { character: '\\ea67' });
|
||||
export const personOutline = new Codicon('person-outline', { character: '\\ea67' });
|
||||
export const personFilled = new Codicon('person-filled', { character: '\\ea67' });
|
||||
export const gitBranch = new Codicon('git-branch', { character: '\\ea68' });
|
||||
export const gitBranchCreate = new Codicon('git-branch-create', { character: '\\ea68' });
|
||||
export const gitBranchDelete = new Codicon('git-branch-delete', { character: '\\ea68' });
|
||||
export const sourceControl = new Codicon('source-control', { character: '\\ea68' });
|
||||
export const mirror = new Codicon('mirror', { character: '\\ea69' });
|
||||
export const mirrorPublic = new Codicon('mirror-public', { character: '\\ea69' });
|
||||
export const star = new Codicon('star', { character: '\\ea6a' });
|
||||
export const starAdd = new Codicon('star-add', { character: '\\ea6a' });
|
||||
export const starDelete = new Codicon('star-delete', { character: '\\ea6a' });
|
||||
export const starEmpty = new Codicon('star-empty', { character: '\\ea6a' });
|
||||
export const comment = new Codicon('comment', { character: '\\ea6b' });
|
||||
export const commentAdd = new Codicon('comment-add', { character: '\\ea6b' });
|
||||
export const alert = new Codicon('alert', { character: '\\ea6c' });
|
||||
export const warning = new Codicon('warning', { character: '\\ea6c' });
|
||||
export const search = new Codicon('search', { character: '\\ea6d' });
|
||||
export const searchSave = new Codicon('search-save', { character: '\\ea6d' });
|
||||
export const logOut = new Codicon('log-out', { character: '\\ea6e' });
|
||||
export const signOut = new Codicon('sign-out', { character: '\\ea6e' });
|
||||
export const logIn = new Codicon('log-in', { character: '\\ea6f' });
|
||||
export const signIn = new Codicon('sign-in', { character: '\\ea6f' });
|
||||
export const eye = new Codicon('eye', { character: '\\ea70' });
|
||||
export const eyeUnwatch = new Codicon('eye-unwatch', { character: '\\ea70' });
|
||||
export const eyeWatch = new Codicon('eye-watch', { character: '\\ea70' });
|
||||
export const circleFilled = new Codicon('circle-filled', { character: '\\ea71' });
|
||||
export const primitiveDot = new Codicon('primitive-dot', { character: '\\ea71' });
|
||||
export const closeDirty = new Codicon('close-dirty', { character: '\\ea71' });
|
||||
export const debugBreakpoint = new Codicon('debug-breakpoint', { character: '\\ea71' });
|
||||
export const debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', { character: '\\ea71' });
|
||||
export const debugHint = new Codicon('debug-hint', { character: '\\ea71' });
|
||||
export const primitiveSquare = new Codicon('primitive-square', { character: '\\ea72' });
|
||||
export const edit = new Codicon('edit', { character: '\\ea73' });
|
||||
export const pencil = new Codicon('pencil', { character: '\\ea73' });
|
||||
export const info = new Codicon('info', { character: '\\ea74' });
|
||||
export const issueOpened = new Codicon('issue-opened', { character: '\\ea74' });
|
||||
export const gistPrivate = new Codicon('gist-private', { character: '\\ea75' });
|
||||
export const gitForkPrivate = new Codicon('git-fork-private', { character: '\\ea75' });
|
||||
export const lock = new Codicon('lock', { character: '\\ea75' });
|
||||
export const mirrorPrivate = new Codicon('mirror-private', { character: '\\ea75' });
|
||||
export const close = new Codicon('close', { character: '\\ea76' });
|
||||
export const removeClose = new Codicon('remove-close', { character: '\\ea76' });
|
||||
export const x = new Codicon('x', { character: '\\ea76' });
|
||||
export const repoSync = new Codicon('repo-sync', { character: '\\ea77' });
|
||||
export const sync = new Codicon('sync', { character: '\\ea77' });
|
||||
export const clone = new Codicon('clone', { character: '\\ea78' });
|
||||
export const desktopDownload = new Codicon('desktop-download', { character: '\\ea78' });
|
||||
export const beaker = new Codicon('beaker', { character: '\\ea79' });
|
||||
export const microscope = new Codicon('microscope', { character: '\\ea79' });
|
||||
export const vm = new Codicon('vm', { character: '\\ea7a' });
|
||||
export const deviceDesktop = new Codicon('device-desktop', { character: '\\ea7a' });
|
||||
export const file = new Codicon('file', { character: '\\ea7b' });
|
||||
export const fileText = new Codicon('file-text', { character: '\\ea7b' });
|
||||
export const more = new Codicon('more', { character: '\\ea7c' });
|
||||
export const ellipsis = new Codicon('ellipsis', { character: '\\ea7c' });
|
||||
export const kebabHorizontal = new Codicon('kebab-horizontal', { character: '\\ea7c' });
|
||||
export const mailReply = new Codicon('mail-reply', { character: '\\ea7d' });
|
||||
export const reply = new Codicon('reply', { character: '\\ea7d' });
|
||||
export const organization = new Codicon('organization', { character: '\\ea7e' });
|
||||
export const organizationFilled = new Codicon('organization-filled', { character: '\\ea7e' });
|
||||
export const organizationOutline = new Codicon('organization-outline', { character: '\\ea7e' });
|
||||
export const newFile = new Codicon('new-file', { character: '\\ea7f' });
|
||||
export const fileAdd = new Codicon('file-add', { character: '\\ea7f' });
|
||||
export const newFolder = new Codicon('new-folder', { character: '\\ea80' });
|
||||
export const fileDirectoryCreate = new Codicon('file-directory-create', { character: '\\ea80' });
|
||||
export const trash = new Codicon('trash', { character: '\\ea81' });
|
||||
export const trashcan = new Codicon('trashcan', { character: '\\ea81' });
|
||||
export const history = new Codicon('history', { character: '\\ea82' });
|
||||
export const clock = new Codicon('clock', { character: '\\ea82' });
|
||||
export const folder = new Codicon('folder', { character: '\\ea83' });
|
||||
export const fileDirectory = new Codicon('file-directory', { character: '\\ea83' });
|
||||
export const symbolFolder = new Codicon('symbol-folder', { character: '\\ea83' });
|
||||
export const logoGithub = new Codicon('logo-github', { character: '\\ea84' });
|
||||
export const markGithub = new Codicon('mark-github', { character: '\\ea84' });
|
||||
export const github = new Codicon('github', { character: '\\ea84' });
|
||||
export const terminal = new Codicon('terminal', { character: '\\ea85' });
|
||||
export const console = new Codicon('console', { character: '\\ea85' });
|
||||
export const repl = new Codicon('repl', { character: '\\ea85' });
|
||||
export const zap = new Codicon('zap', { character: '\\ea86' });
|
||||
export const symbolEvent = new Codicon('symbol-event', { character: '\\ea86' });
|
||||
export const error = new Codicon('error', { character: '\\ea87' });
|
||||
export const stop = new Codicon('stop', { character: '\\ea87' });
|
||||
export const variable = new Codicon('variable', { character: '\\ea88' });
|
||||
export const symbolVariable = new Codicon('symbol-variable', { character: '\\ea88' });
|
||||
export const array = new Codicon('array', { character: '\\ea8a' });
|
||||
export const symbolArray = new Codicon('symbol-array', { character: '\\ea8a' });
|
||||
export const symbolModule = new Codicon('symbol-module', { character: '\\ea8b' });
|
||||
export const symbolPackage = new Codicon('symbol-package', { character: '\\ea8b' });
|
||||
export const symbolNamespace = new Codicon('symbol-namespace', { character: '\\ea8b' });
|
||||
export const symbolObject = new Codicon('symbol-object', { character: '\\ea8b' });
|
||||
export const symbolMethod = new Codicon('symbol-method', { character: '\\ea8c' });
|
||||
export const symbolFunction = new Codicon('symbol-function', { character: '\\ea8c' });
|
||||
export const symbolConstructor = new Codicon('symbol-constructor', { character: '\\ea8c' });
|
||||
export const symbolBoolean = new Codicon('symbol-boolean', { character: '\\ea8f' });
|
||||
export const symbolNull = new Codicon('symbol-null', { character: '\\ea8f' });
|
||||
export const symbolNumeric = new Codicon('symbol-numeric', { character: '\\ea90' });
|
||||
export const symbolNumber = new Codicon('symbol-number', { character: '\\ea90' });
|
||||
export const symbolStructure = new Codicon('symbol-structure', { character: '\\ea91' });
|
||||
export const symbolStruct = new Codicon('symbol-struct', { character: '\\ea91' });
|
||||
export const symbolParameter = new Codicon('symbol-parameter', { character: '\\ea92' });
|
||||
export const symbolTypeParameter = new Codicon('symbol-type-parameter', { character: '\\ea92' });
|
||||
export const symbolKey = new Codicon('symbol-key', { character: '\\ea93' });
|
||||
export const symbolText = new Codicon('symbol-text', { character: '\\ea93' });
|
||||
export const symbolReference = new Codicon('symbol-reference', { character: '\\ea94' });
|
||||
export const goToFile = new Codicon('go-to-file', { character: '\\ea94' });
|
||||
export const symbolEnum = new Codicon('symbol-enum', { character: '\\ea95' });
|
||||
export const symbolValue = new Codicon('symbol-value', { character: '\\ea95' });
|
||||
export const symbolRuler = new Codicon('symbol-ruler', { character: '\\ea96' });
|
||||
export const symbolUnit = new Codicon('symbol-unit', { character: '\\ea96' });
|
||||
export const activateBreakpoints = new Codicon('activate-breakpoints', { character: '\\ea97' });
|
||||
export const archive = new Codicon('archive', { character: '\\ea98' });
|
||||
export const arrowBoth = new Codicon('arrow-both', { character: '\\ea99' });
|
||||
export const arrowDown = new Codicon('arrow-down', { character: '\\ea9a' });
|
||||
export const arrowLeft = new Codicon('arrow-left', { character: '\\ea9b' });
|
||||
export const arrowRight = new Codicon('arrow-right', { character: '\\ea9c' });
|
||||
export const arrowSmallDown = new Codicon('arrow-small-down', { character: '\\ea9d' });
|
||||
export const arrowSmallLeft = new Codicon('arrow-small-left', { character: '\\ea9e' });
|
||||
export const arrowSmallRight = new Codicon('arrow-small-right', { character: '\\ea9f' });
|
||||
export const arrowSmallUp = new Codicon('arrow-small-up', { character: '\\eaa0' });
|
||||
export const arrowUp = new Codicon('arrow-up', { character: '\\eaa1' });
|
||||
export const bell = new Codicon('bell', { character: '\\eaa2' });
|
||||
export const bold = new Codicon('bold', { character: '\\eaa3' });
|
||||
export const book = new Codicon('book', { character: '\\eaa4' });
|
||||
export const bookmark = new Codicon('bookmark', { character: '\\eaa5' });
|
||||
export const debugBreakpointConditionalUnverified = new Codicon('debug-breakpoint-conditional-unverified', { character: '\\eaa6' });
|
||||
export const debugBreakpointConditional = new Codicon('debug-breakpoint-conditional', { character: '\\eaa7' });
|
||||
export const debugBreakpointConditionalDisabled = new Codicon('debug-breakpoint-conditional-disabled', { character: '\\eaa7' });
|
||||
export const debugBreakpointDataUnverified = new Codicon('debug-breakpoint-data-unverified', { character: '\\eaa8' });
|
||||
export const debugBreakpointData = new Codicon('debug-breakpoint-data', { character: '\\eaa9' });
|
||||
export const debugBreakpointDataDisabled = new Codicon('debug-breakpoint-data-disabled', { character: '\\eaa9' });
|
||||
export const debugBreakpointLogUnverified = new Codicon('debug-breakpoint-log-unverified', { character: '\\eaaa' });
|
||||
export const debugBreakpointLog = new Codicon('debug-breakpoint-log', { character: '\\eaab' });
|
||||
export const debugBreakpointLogDisabled = new Codicon('debug-breakpoint-log-disabled', { character: '\\eaab' });
|
||||
export const briefcase = new Codicon('briefcase', { character: '\\eaac' });
|
||||
export const broadcast = new Codicon('broadcast', { character: '\\eaad' });
|
||||
export const browser = new Codicon('browser', { character: '\\eaae' });
|
||||
export const bug = new Codicon('bug', { character: '\\eaaf' });
|
||||
export const calendar = new Codicon('calendar', { character: '\\eab0' });
|
||||
export const caseSensitive = new Codicon('case-sensitive', { character: '\\eab1' });
|
||||
export const check = new Codicon('check', { character: '\\eab2' });
|
||||
export const checklist = new Codicon('checklist', { character: '\\eab3' });
|
||||
export const chevronDown = new Codicon('chevron-down', { character: '\\eab4' });
|
||||
export const chevronLeft = new Codicon('chevron-left', { character: '\\eab5' });
|
||||
export const chevronRight = new Codicon('chevron-right', { character: '\\eab6' });
|
||||
export const chevronUp = new Codicon('chevron-up', { character: '\\eab7' });
|
||||
export const chromeClose = new Codicon('chrome-close', { character: '\\eab8' });
|
||||
export const chromeMaximize = new Codicon('chrome-maximize', { character: '\\eab9' });
|
||||
export const chromeMinimize = new Codicon('chrome-minimize', { character: '\\eaba' });
|
||||
export const chromeRestore = new Codicon('chrome-restore', { character: '\\eabb' });
|
||||
export const circleOutline = new Codicon('circle-outline', { character: '\\eabc' });
|
||||
export const debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', { character: '\\eabc' });
|
||||
export const circleSlash = new Codicon('circle-slash', { character: '\\eabd' });
|
||||
export const circuitBoard = new Codicon('circuit-board', { character: '\\eabe' });
|
||||
export const clearAll = new Codicon('clear-all', { character: '\\eabf' });
|
||||
export const clippy = new Codicon('clippy', { character: '\\eac0' });
|
||||
export const closeAll = new Codicon('close-all', { character: '\\eac1' });
|
||||
export const cloudDownload = new Codicon('cloud-download', { character: '\\eac2' });
|
||||
export const cloudUpload = new Codicon('cloud-upload', { character: '\\eac3' });
|
||||
export const code = new Codicon('code', { character: '\\eac4' });
|
||||
export const collapseAll = new Codicon('collapse-all', { character: '\\eac5' });
|
||||
export const colorMode = new Codicon('color-mode', { character: '\\eac6' });
|
||||
export const commentDiscussion = new Codicon('comment-discussion', { character: '\\eac7' });
|
||||
export const compareChanges = new Codicon('compare-changes', { character: '\\eac8' });
|
||||
export const creditCard = new Codicon('credit-card', { character: '\\eac9' });
|
||||
export const dash = new Codicon('dash', { character: '\\eacc' });
|
||||
export const dashboard = new Codicon('dashboard', { character: '\\eacd' });
|
||||
export const database = new Codicon('database', { character: '\\eace' });
|
||||
export const debugContinue = new Codicon('debug-continue', { character: '\\eacf' });
|
||||
export const debugDisconnect = new Codicon('debug-disconnect', { character: '\\ead0' });
|
||||
export const debugPause = new Codicon('debug-pause', { character: '\\ead1' });
|
||||
export const debugRestart = new Codicon('debug-restart', { character: '\\ead2' });
|
||||
export const debugStart = new Codicon('debug-start', { character: '\\ead3' });
|
||||
export const debugStepInto = new Codicon('debug-step-into', { character: '\\ead4' });
|
||||
export const debugStepOut = new Codicon('debug-step-out', { character: '\\ead5' });
|
||||
export const debugStepOver = new Codicon('debug-step-over', { character: '\\ead6' });
|
||||
export const debugStop = new Codicon('debug-stop', { character: '\\ead7' });
|
||||
export const debug = new Codicon('debug', { character: '\\ead8' });
|
||||
export const deviceCameraVideo = new Codicon('device-camera-video', { character: '\\ead9' });
|
||||
export const deviceCamera = new Codicon('device-camera', { character: '\\eada' });
|
||||
export const deviceMobile = new Codicon('device-mobile', { character: '\\eadb' });
|
||||
export const diffAdded = new Codicon('diff-added', { character: '\\eadc' });
|
||||
export const diffIgnored = new Codicon('diff-ignored', { character: '\\eadd' });
|
||||
export const diffModified = new Codicon('diff-modified', { character: '\\eade' });
|
||||
export const diffRemoved = new Codicon('diff-removed', { character: '\\eadf' });
|
||||
export const diffRenamed = new Codicon('diff-renamed', { character: '\\eae0' });
|
||||
export const diff = new Codicon('diff', { character: '\\eae1' });
|
||||
export const discard = new Codicon('discard', { character: '\\eae2' });
|
||||
export const editorLayout = new Codicon('editor-layout', { character: '\\eae3' });
|
||||
export const emptyWindow = new Codicon('empty-window', { character: '\\eae4' });
|
||||
export const exclude = new Codicon('exclude', { character: '\\eae5' });
|
||||
export const extensions = new Codicon('extensions', { character: '\\eae6' });
|
||||
export const eyeClosed = new Codicon('eye-closed', { character: '\\eae7' });
|
||||
export const fileBinary = new Codicon('file-binary', { character: '\\eae8' });
|
||||
export const fileCode = new Codicon('file-code', { character: '\\eae9' });
|
||||
export const fileMedia = new Codicon('file-media', { character: '\\eaea' });
|
||||
export const filePdf = new Codicon('file-pdf', { character: '\\eaeb' });
|
||||
export const fileSubmodule = new Codicon('file-submodule', { character: '\\eaec' });
|
||||
export const fileSymlinkDirectory = new Codicon('file-symlink-directory', { character: '\\eaed' });
|
||||
export const fileSymlinkFile = new Codicon('file-symlink-file', { character: '\\eaee' });
|
||||
export const fileZip = new Codicon('file-zip', { character: '\\eaef' });
|
||||
export const files = new Codicon('files', { character: '\\eaf0' });
|
||||
export const filter = new Codicon('filter', { character: '\\eaf1' });
|
||||
export const flame = new Codicon('flame', { character: '\\eaf2' });
|
||||
export const foldDown = new Codicon('fold-down', { character: '\\eaf3' });
|
||||
export const foldUp = new Codicon('fold-up', { character: '\\eaf4' });
|
||||
export const fold = new Codicon('fold', { character: '\\eaf5' });
|
||||
export const folderActive = new Codicon('folder-active', { character: '\\eaf6' });
|
||||
export const folderOpened = new Codicon('folder-opened', { character: '\\eaf7' });
|
||||
export const gear = new Codicon('gear', { character: '\\eaf8' });
|
||||
export const gift = new Codicon('gift', { character: '\\eaf9' });
|
||||
export const gistSecret = new Codicon('gist-secret', { character: '\\eafa' });
|
||||
export const gist = new Codicon('gist', { character: '\\eafb' });
|
||||
export const gitCommit = new Codicon('git-commit', { character: '\\eafc' });
|
||||
export const gitCompare = new Codicon('git-compare', { character: '\\eafd' });
|
||||
export const gitMerge = new Codicon('git-merge', { character: '\\eafe' });
|
||||
export const githubAction = new Codicon('github-action', { character: '\\eaff' });
|
||||
export const githubAlt = new Codicon('github-alt', { character: '\\eb00' });
|
||||
export const globe = new Codicon('globe', { character: '\\eb01' });
|
||||
export const grabber = new Codicon('grabber', { character: '\\eb02' });
|
||||
export const graph = new Codicon('graph', { character: '\\eb03' });
|
||||
export const gripper = new Codicon('gripper', { character: '\\eb04' });
|
||||
export const heart = new Codicon('heart', { character: '\\eb05' });
|
||||
export const home = new Codicon('home', { character: '\\eb06' });
|
||||
export const horizontalRule = new Codicon('horizontal-rule', { character: '\\eb07' });
|
||||
export const hubot = new Codicon('hubot', { character: '\\eb08' });
|
||||
export const inbox = new Codicon('inbox', { character: '\\eb09' });
|
||||
export const issueClosed = new Codicon('issue-closed', { character: '\\eb0a' });
|
||||
export const issueReopened = new Codicon('issue-reopened', { character: '\\eb0b' });
|
||||
export const issues = new Codicon('issues', { character: '\\eb0c' });
|
||||
export const italic = new Codicon('italic', { character: '\\eb0d' });
|
||||
export const jersey = new Codicon('jersey', { character: '\\eb0e' });
|
||||
export const json = new Codicon('json', { character: '\\eb0f' });
|
||||
export const kebabVertical = new Codicon('kebab-vertical', { character: '\\eb10' });
|
||||
export const key = new Codicon('key', { character: '\\eb11' });
|
||||
export const law = new Codicon('law', { character: '\\eb12' });
|
||||
export const lightbulbAutofix = new Codicon('lightbulb-autofix', { character: '\\eb13' });
|
||||
export const linkExternal = new Codicon('link-external', { character: '\\eb14' });
|
||||
export const link = new Codicon('link', { character: '\\eb15' });
|
||||
export const listOrdered = new Codicon('list-ordered', { character: '\\eb16' });
|
||||
export const listUnordered = new Codicon('list-unordered', { character: '\\eb17' });
|
||||
export const liveShare = new Codicon('live-share', { character: '\\eb18' });
|
||||
export const loading = new Codicon('loading', { character: '\\eb19' });
|
||||
export const location = new Codicon('location', { character: '\\eb1a' });
|
||||
export const mailRead = new Codicon('mail-read', { character: '\\eb1b' });
|
||||
export const mail = new Codicon('mail', { character: '\\eb1c' });
|
||||
export const markdown = new Codicon('markdown', { character: '\\eb1d' });
|
||||
export const megaphone = new Codicon('megaphone', { character: '\\eb1e' });
|
||||
export const mention = new Codicon('mention', { character: '\\eb1f' });
|
||||
export const milestone = new Codicon('milestone', { character: '\\eb20' });
|
||||
export const mortarBoard = new Codicon('mortar-board', { character: '\\eb21' });
|
||||
export const move = new Codicon('move', { character: '\\eb22' });
|
||||
export const multipleWindows = new Codicon('multiple-windows', { character: '\\eb23' });
|
||||
export const mute = new Codicon('mute', { character: '\\eb24' });
|
||||
export const noNewline = new Codicon('no-newline', { character: '\\eb25' });
|
||||
export const note = new Codicon('note', { character: '\\eb26' });
|
||||
export const octoface = new Codicon('octoface', { character: '\\eb27' });
|
||||
export const openPreview = new Codicon('open-preview', { character: '\\eb28' });
|
||||
export const package_ = new Codicon('package', { character: '\\eb29' });
|
||||
export const paintcan = new Codicon('paintcan', { character: '\\eb2a' });
|
||||
export const pin = new Codicon('pin', { character: '\\eb2b' });
|
||||
export const play = new Codicon('play', { character: '\\eb2c' });
|
||||
export const run = new Codicon('run', { character: '\\eb2c' });
|
||||
export const plug = new Codicon('plug', { character: '\\eb2d' });
|
||||
export const preserveCase = new Codicon('preserve-case', { character: '\\eb2e' });
|
||||
export const preview = new Codicon('preview', { character: '\\eb2f' });
|
||||
export const project = new Codicon('project', { character: '\\eb30' });
|
||||
export const pulse = new Codicon('pulse', { character: '\\eb31' });
|
||||
export const question = new Codicon('question', { character: '\\eb32' });
|
||||
export const quote = new Codicon('quote', { character: '\\eb33' });
|
||||
export const radioTower = new Codicon('radio-tower', { character: '\\eb34' });
|
||||
export const reactions = new Codicon('reactions', { character: '\\eb35' });
|
||||
export const references = new Codicon('references', { character: '\\eb36' });
|
||||
export const refresh = new Codicon('refresh', { character: '\\eb37' });
|
||||
export const regex = new Codicon('regex', { character: '\\eb38' });
|
||||
export const remoteExplorer = new Codicon('remote-explorer', { character: '\\eb39' });
|
||||
export const remote = new Codicon('remote', { character: '\\eb3a' });
|
||||
export const remove = new Codicon('remove', { character: '\\eb3b' });
|
||||
export const replaceAll = new Codicon('replace-all', { character: '\\eb3c' });
|
||||
export const replace = new Codicon('replace', { character: '\\eb3d' });
|
||||
export const repoClone = new Codicon('repo-clone', { character: '\\eb3e' });
|
||||
export const repoForcePush = new Codicon('repo-force-push', { character: '\\eb3f' });
|
||||
export const repoPull = new Codicon('repo-pull', { character: '\\eb40' });
|
||||
export const repoPush = new Codicon('repo-push', { character: '\\eb41' });
|
||||
export const report = new Codicon('report', { character: '\\eb42' });
|
||||
export const requestChanges = new Codicon('request-changes', { character: '\\eb43' });
|
||||
export const rocket = new Codicon('rocket', { character: '\\eb44' });
|
||||
export const rootFolderOpened = new Codicon('root-folder-opened', { character: '\\eb45' });
|
||||
export const rootFolder = new Codicon('root-folder', { character: '\\eb46' });
|
||||
export const rss = new Codicon('rss', { character: '\\eb47' });
|
||||
export const ruby = new Codicon('ruby', { character: '\\eb48' });
|
||||
export const saveAll = new Codicon('save-all', { character: '\\eb49' });
|
||||
export const saveAs = new Codicon('save-as', { character: '\\eb4a' });
|
||||
export const save = new Codicon('save', { character: '\\eb4b' });
|
||||
export const screenFull = new Codicon('screen-full', { character: '\\eb4c' });
|
||||
export const screenNormal = new Codicon('screen-normal', { character: '\\eb4d' });
|
||||
export const searchStop = new Codicon('search-stop', { character: '\\eb4e' });
|
||||
export const server = new Codicon('server', { character: '\\eb50' });
|
||||
export const settingsGear = new Codicon('settings-gear', { character: '\\eb51' });
|
||||
export const settings = new Codicon('settings', { character: '\\eb52' });
|
||||
export const shield = new Codicon('shield', { character: '\\eb53' });
|
||||
export const smiley = new Codicon('smiley', { character: '\\eb54' });
|
||||
export const sortPrecedence = new Codicon('sort-precedence', { character: '\\eb55' });
|
||||
export const splitHorizontal = new Codicon('split-horizontal', { character: '\\eb56' });
|
||||
export const splitVertical = new Codicon('split-vertical', { character: '\\eb57' });
|
||||
export const squirrel = new Codicon('squirrel', { character: '\\eb58' });
|
||||
export const starFull = new Codicon('star-full', { character: '\\eb59' });
|
||||
export const starHalf = new Codicon('star-half', { character: '\\eb5a' });
|
||||
export const symbolClass = new Codicon('symbol-class', { character: '\\eb5b' });
|
||||
export const symbolColor = new Codicon('symbol-color', { character: '\\eb5c' });
|
||||
export const symbolConstant = new Codicon('symbol-constant', { character: '\\eb5d' });
|
||||
export const symbolEnumMember = new Codicon('symbol-enum-member', { character: '\\eb5e' });
|
||||
export const symbolField = new Codicon('symbol-field', { character: '\\eb5f' });
|
||||
export const symbolFile = new Codicon('symbol-file', { character: '\\eb60' });
|
||||
export const symbolInterface = new Codicon('symbol-interface', { character: '\\eb61' });
|
||||
export const symbolKeyword = new Codicon('symbol-keyword', { character: '\\eb62' });
|
||||
export const symbolMisc = new Codicon('symbol-misc', { character: '\\eb63' });
|
||||
export const symbolOperator = new Codicon('symbol-operator', { character: '\\eb64' });
|
||||
export const symbolProperty = new Codicon('symbol-property', { character: '\\eb65' });
|
||||
export const wrench = new Codicon('wrench', { character: '\\eb65' });
|
||||
export const wrenchSubaction = new Codicon('wrench-subaction', { character: '\\eb65' });
|
||||
export const symbolSnippet = new Codicon('symbol-snippet', { character: '\\eb66' });
|
||||
export const tasklist = new Codicon('tasklist', { character: '\\eb67' });
|
||||
export const telescope = new Codicon('telescope', { character: '\\eb68' });
|
||||
export const textSize = new Codicon('text-size', { character: '\\eb69' });
|
||||
export const threeBars = new Codicon('three-bars', { character: '\\eb6a' });
|
||||
export const thumbsdown = new Codicon('thumbsdown', { character: '\\eb6b' });
|
||||
export const thumbsup = new Codicon('thumbsup', { character: '\\eb6c' });
|
||||
export const tools = new Codicon('tools', { character: '\\eb6d' });
|
||||
export const triangleDown = new Codicon('triangle-down', { character: '\\eb6e' });
|
||||
export const triangleLeft = new Codicon('triangle-left', { character: '\\eb6f' });
|
||||
export const triangleRight = new Codicon('triangle-right', { character: '\\eb70' });
|
||||
export const triangleUp = new Codicon('triangle-up', { character: '\\eb71' });
|
||||
export const twitter = new Codicon('twitter', { character: '\\eb72' });
|
||||
export const unfold = new Codicon('unfold', { character: '\\eb73' });
|
||||
export const unlock = new Codicon('unlock', { character: '\\eb74' });
|
||||
export const unmute = new Codicon('unmute', { character: '\\eb75' });
|
||||
export const unverified = new Codicon('unverified', { character: '\\eb76' });
|
||||
export const verified = new Codicon('verified', { character: '\\eb77' });
|
||||
export const versions = new Codicon('versions', { character: '\\eb78' });
|
||||
export const vmActive = new Codicon('vm-active', { character: '\\eb79' });
|
||||
export const vmOutline = new Codicon('vm-outline', { character: '\\eb7a' });
|
||||
export const vmRunning = new Codicon('vm-running', { character: '\\eb7b' });
|
||||
export const watch = new Codicon('watch', { character: '\\eb7c' });
|
||||
export const whitespace = new Codicon('whitespace', { character: '\\eb7d' });
|
||||
export const wholeWord = new Codicon('whole-word', { character: '\\eb7e' });
|
||||
export const window = new Codicon('window', { character: '\\eb7f' });
|
||||
export const wordWrap = new Codicon('word-wrap', { character: '\\eb80' });
|
||||
export const zoomIn = new Codicon('zoom-in', { character: '\\eb81' });
|
||||
export const zoomOut = new Codicon('zoom-out', { character: '\\eb82' });
|
||||
export const listFilter = new Codicon('list-filter', { character: '\\eb83' });
|
||||
export const listFlat = new Codicon('list-flat', { character: '\\eb84' });
|
||||
export const listSelection = new Codicon('list-selection', { character: '\\eb85' });
|
||||
export const selection = new Codicon('selection', { character: '\\eb85' });
|
||||
export const listTree = new Codicon('list-tree', { character: '\\eb86' });
|
||||
export const debugBreakpointFunctionUnverified = new Codicon('debug-breakpoint-function-unverified', { character: '\\eb87' });
|
||||
export const debugBreakpointFunction = new Codicon('debug-breakpoint-function', { character: '\\eb88' });
|
||||
export const debugBreakpointFunctionDisabled = new Codicon('debug-breakpoint-function-disabled', { character: '\\eb88' });
|
||||
export const debugStackframeActive = new Codicon('debug-stackframe-active', { character: '\\eb89' });
|
||||
export const debugStackframeDot = new Codicon('debug-stackframe-dot', { character: '\\eb8a' });
|
||||
export const debugStackframe = new Codicon('debug-stackframe', { character: '\\eb8b' });
|
||||
export const debugStackframeFocused = new Codicon('debug-stackframe-focused', { character: '\\eb8b' });
|
||||
export const debugBreakpointUnsupported = new Codicon('debug-breakpoint-unsupported', { character: '\\eb8c' });
|
||||
export const symbolString = new Codicon('symbol-string', { character: '\\eb8d' });
|
||||
export const debugReverseContinue = new Codicon('debug-reverse-continue', { character: '\\eb8e' });
|
||||
export const debugStepBack = new Codicon('debug-step-back', { character: '\\eb8f' });
|
||||
export const debugRestartFrame = new Codicon('debug-restart-frame', { character: '\\eb90' });
|
||||
export const debugAlternate = new Codicon('debug-alternate', { character: '\\eb91' });
|
||||
export const callIncoming = new Codicon('call-incoming', { character: '\\eb92' });
|
||||
export const callOutgoing = new Codicon('call-outgoing', { character: '\\eb93' });
|
||||
export const menu = new Codicon('menu', { character: '\\eb94' });
|
||||
export const expandAll = new Codicon('expand-all', { character: '\\eb95' });
|
||||
export const feedback = new Codicon('feedback', { character: '\\eb96' });
|
||||
export const groupByRefType = new Codicon('group-by-ref-type', { character: '\\eb97' });
|
||||
export const ungroupByRefType = new Codicon('ungroup-by-ref-type', { character: '\\eb98' });
|
||||
export const account = new Codicon('account', { character: '\\eb99' });
|
||||
export const bellDot = new Codicon('bell-dot', { character: '\\eb9a' });
|
||||
export const debugConsole = new Codicon('debug-console', { character: '\\eb9b' });
|
||||
export const library = new Codicon('library', { character: '\\eb9c' });
|
||||
export const output = new Codicon('output', { character: '\\eb9d' });
|
||||
export const runAll = new Codicon('run-all', { character: '\\eb9e' });
|
||||
export const syncIgnored = new Codicon('sync-ignored', { character: '\\eb9f' });
|
||||
export const pinned = new Codicon('pinned', { character: '\\eba0' });
|
||||
export const githubInverted = new Codicon('github-inverted', { character: '\\eba1' });
|
||||
export const debugAlt2 = new Codicon('debug-alt-2', { character: '\\f101' });
|
||||
export const debugAlt = new Codicon('debug-alt', { character: '\\f102' });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const escapeCodiconsRegex = /(\\)?\$\([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?\)/gi;
|
||||
export function escapeCodicons(text: string): string {
|
||||
|
||||
@@ -404,10 +404,10 @@ export function createMatches(score: undefined | FuzzyScore, offset = 0): IMatch
|
||||
for (let pos = wordStart; pos < _maxLen; pos++) {
|
||||
if (matches[matches.length - (pos + 1)] === '1') {
|
||||
const last = res[res.length - 1];
|
||||
if (last && last.end === pos) {
|
||||
last.end = pos + 1;
|
||||
if (last && last.end === pos + offset) {
|
||||
last.end = pos + offset + 1;
|
||||
} else {
|
||||
res.push({ start: pos + offset, end: pos + 1 + offset });
|
||||
res.push({ start: pos + offset, end: pos + offset + 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ function doScoreFuzzy(query: string, queryLower: string, queryLength: number, ta
|
||||
function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: string, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number {
|
||||
let score = 0;
|
||||
|
||||
if (queryLowerCharAtIndex !== targetLower[targetIndex]) {
|
||||
if (!considerAsEqual(queryLowerCharAtIndex, targetLower[targetIndex])) {
|
||||
return score; // no match of characters
|
||||
}
|
||||
|
||||
@@ -228,6 +228,19 @@ function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: strin
|
||||
return score;
|
||||
}
|
||||
|
||||
function considerAsEqual(a: string, b: string): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special case path spearators: ignore platform differences
|
||||
if (a === '/' || a === '\\') {
|
||||
return b === '/' || b === '\\';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function scoreSeparatorAtPos(charCode: number): number {
|
||||
switch (charCode) {
|
||||
case CharCode.Slash:
|
||||
@@ -264,15 +277,16 @@ function scoreSeparatorAtPos(charCode: number): number {
|
||||
|
||||
//#region Alternate fuzzy scorer implementation that is e.g. used for symbols
|
||||
|
||||
export type FuzzyScore2 = [number /* score*/, IMatch[]];
|
||||
export type FuzzyScore2 = [number | undefined /* score */, IMatch[]];
|
||||
|
||||
const NO_SCORE2: FuzzyScore2 = [NO_MATCH, []];
|
||||
const NO_SCORE2: FuzzyScore2 = [undefined, []];
|
||||
|
||||
export function scoreFuzzy2(target: string, query: IPreparedQuery, patternStart = 0, matchOffset = 0): FuzzyScore2 {
|
||||
export function scoreFuzzy2(target: string, query: IPreparedQuery | IPreparedQueryPiece, patternStart = 0, matchOffset = 0): FuzzyScore2 {
|
||||
|
||||
// Score: multiple inputs
|
||||
if (query.values && query.values.length > 1) {
|
||||
return doScoreFuzzy2Multiple(target, query.values, patternStart, matchOffset);
|
||||
const preparedQuery = query as IPreparedQuery;
|
||||
if (preparedQuery.values && preparedQuery.values.length > 1) {
|
||||
return doScoreFuzzy2Multiple(target, preparedQuery.values, patternStart, matchOffset);
|
||||
}
|
||||
|
||||
// Score: single input
|
||||
@@ -285,7 +299,7 @@ function doScoreFuzzy2Multiple(target: string, query: IPreparedQueryPiece[], pat
|
||||
|
||||
for (const queryPiece of query) {
|
||||
const [score, matches] = doScoreFuzzy2Single(target, queryPiece, patternStart, matchOffset);
|
||||
if (!score) {
|
||||
if (typeof score !== 'number') {
|
||||
// if a single query value does not match, return with
|
||||
// no score entirely, we require all queries to match
|
||||
return NO_SCORE2;
|
||||
@@ -796,9 +810,14 @@ export interface IPreparedQueryPiece {
|
||||
|
||||
export interface IPreparedQuery extends IPreparedQueryPiece {
|
||||
|
||||
// Split by spaces
|
||||
/**
|
||||
* Query split by spaces into pieces.
|
||||
*/
|
||||
values: IPreparedQueryPiece[] | undefined;
|
||||
|
||||
/**
|
||||
* Wether the query contains path separator(s) or not.
|
||||
*/
|
||||
containsPathSeparator: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
export namespace Iterable {
|
||||
|
||||
const _empty: Iterable<any> = Object.freeze([]);
|
||||
export function empty<T>(): Iterable<T> {
|
||||
export function empty<T = any>(): Iterable<T> {
|
||||
return _empty;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { compareIgnoreCase, compare } from 'vs/base/common/strings';
|
||||
import { compareSubstringIgnoreCase, compare, compareSubstring } from 'vs/base/common/strings';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
|
||||
/**
|
||||
* @deprecated ES6: use `[...SetOrMap.values()]`
|
||||
@@ -102,7 +104,10 @@ export class PathIterator implements IKeyIterator<string> {
|
||||
private _from!: number;
|
||||
private _to!: number;
|
||||
|
||||
constructor(private _splitOnBackslash: boolean = true) { }
|
||||
constructor(
|
||||
private readonly _splitOnBackslash: boolean = true,
|
||||
private readonly _caseSensitive: boolean = true
|
||||
) { }
|
||||
|
||||
reset(key: string): this {
|
||||
this._value = key.replace(/\\$|\/$/, '');
|
||||
@@ -135,27 +140,9 @@ export class PathIterator implements IKeyIterator<string> {
|
||||
}
|
||||
|
||||
cmp(a: string): number {
|
||||
|
||||
let aPos = 0;
|
||||
const aLen = a.length;
|
||||
let thisPos = this._from;
|
||||
|
||||
while (aPos < aLen && thisPos < this._to) {
|
||||
const cmp = a.charCodeAt(aPos) - this._value.charCodeAt(thisPos);
|
||||
if (cmp !== 0) {
|
||||
return cmp;
|
||||
}
|
||||
aPos += 1;
|
||||
thisPos += 1;
|
||||
}
|
||||
|
||||
if (aLen === this._to - this._from) {
|
||||
return 0;
|
||||
} else if (aPos < aLen) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
return this._caseSensitive
|
||||
? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
|
||||
: compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
|
||||
}
|
||||
|
||||
value(): string {
|
||||
@@ -169,7 +156,7 @@ const enum UriIteratorState {
|
||||
|
||||
export class UriIterator implements IKeyIterator<URI> {
|
||||
|
||||
private _pathIterator = new PathIterator(false);
|
||||
private _pathIterator!: PathIterator;
|
||||
private _value!: URI;
|
||||
private _states: UriIteratorState[] = [];
|
||||
private _stateIdx: number = 0;
|
||||
@@ -184,6 +171,10 @@ export class UriIterator implements IKeyIterator<URI> {
|
||||
this._states.push(UriIteratorState.Authority);
|
||||
}
|
||||
if (this._value.path) {
|
||||
//todo@jrieken the case-sensitive logic is copied form `resources.ts#hasToIgnoreCase`
|
||||
// which cannot be used because it depends on this
|
||||
const caseSensitive = key.scheme === Schemas.file && isLinux;
|
||||
this._pathIterator = new PathIterator(false, caseSensitive);
|
||||
this._pathIterator.reset(key.path);
|
||||
if (this._pathIterator.value()) {
|
||||
this._states.push(UriIteratorState.Path);
|
||||
@@ -215,9 +206,9 @@ export class UriIterator implements IKeyIterator<URI> {
|
||||
|
||||
cmp(a: string): number {
|
||||
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
|
||||
return compareIgnoreCase(a, this._value.scheme);
|
||||
return compareSubstringIgnoreCase(a, this._value.scheme);
|
||||
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
|
||||
return compareIgnoreCase(a, this._value.authority);
|
||||
return compareSubstringIgnoreCase(a, this._value.authority);
|
||||
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
|
||||
return this._pathIterator.cmp(a);
|
||||
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
|
||||
|
||||
@@ -18,3 +18,19 @@ export class Counter {
|
||||
return this._next++;
|
||||
}
|
||||
}
|
||||
|
||||
export class MovingAverage {
|
||||
|
||||
private _n = 1;
|
||||
private _val = 0;
|
||||
|
||||
update(value: number): this {
|
||||
this._val = this._val + (value - this._val) / this._n;
|
||||
this._n += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this._val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ export namespace DataUri {
|
||||
export class ResourceGlobMatcher {
|
||||
|
||||
private readonly globalExpression: ParsedExpression;
|
||||
private readonly expressionsByRoot: TernarySearchTree<string, { root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
|
||||
private readonly expressionsByRoot: TernarySearchTree<URI, { root: URI, expression: ParsedExpression }> = TernarySearchTree.forUris<{ root: URI, expression: ParsedExpression }>();
|
||||
|
||||
constructor(
|
||||
globalExpression: IExpression,
|
||||
@@ -325,12 +325,12 @@ export class ResourceGlobMatcher {
|
||||
) {
|
||||
this.globalExpression = parse(globalExpression);
|
||||
for (const expression of rootExpressions) {
|
||||
this.expressionsByRoot.set(expression.root.toString(), { root: expression.root, expression: parse(expression.expression) });
|
||||
this.expressionsByRoot.set(expression.root, { root: expression.root, expression: parse(expression.expression) });
|
||||
}
|
||||
}
|
||||
|
||||
matches(resource: URI): boolean {
|
||||
const rootExpression = this.expressionsByRoot.findSubstr(resource.toString());
|
||||
const rootExpression = this.expressionsByRoot.findSubstr(resource);
|
||||
if (rootExpression) {
|
||||
const path = relativePath(rootExpression.root, resource);
|
||||
if (path && !!rootExpression.expression(path)) {
|
||||
|
||||
@@ -102,14 +102,14 @@ export class ScrollState implements IScrollDimensions, IScrollPosition {
|
||||
);
|
||||
}
|
||||
|
||||
public withScrollDimensions(update: INewScrollDimensions): ScrollState {
|
||||
public withScrollDimensions(update: INewScrollDimensions, useRawScrollPositions: boolean): ScrollState {
|
||||
return new ScrollState(
|
||||
(typeof update.width !== 'undefined' ? update.width : this.width),
|
||||
(typeof update.scrollWidth !== 'undefined' ? update.scrollWidth : this.scrollWidth),
|
||||
this.rawScrollLeft,
|
||||
useRawScrollPositions ? this.rawScrollLeft : this.scrollLeft,
|
||||
(typeof update.height !== 'undefined' ? update.height : this.height),
|
||||
(typeof update.scrollHeight !== 'undefined' ? update.scrollHeight : this.scrollHeight),
|
||||
this.rawScrollTop
|
||||
useRawScrollPositions ? this.rawScrollTop : this.scrollTop
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,8 +224,8 @@ export class Scrollable extends Disposable {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public setScrollDimensions(dimensions: INewScrollDimensions): void {
|
||||
const newState = this._state.withScrollDimensions(dimensions);
|
||||
public setScrollDimensions(dimensions: INewScrollDimensions, useRawScrollPositions: boolean): void {
|
||||
const newState = this._state.withScrollDimensions(dimensions, useRawScrollPositions);
|
||||
this._setState(newState);
|
||||
|
||||
// Validate outstanding animated scroll position target
|
||||
|
||||
@@ -295,7 +295,31 @@ export function compare(a: string, b: string): number {
|
||||
}
|
||||
}
|
||||
|
||||
export function compareIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
|
||||
export function compareSubstring(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
|
||||
for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
|
||||
let codeA = a.charCodeAt(aStart);
|
||||
let codeB = b.charCodeAt(bStart);
|
||||
if (codeA < codeB) {
|
||||
return -1;
|
||||
} else if (codeA > codeB) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
const aLen = aEnd - aStart;
|
||||
const bLen = bEnd - bStart;
|
||||
if (aLen < bLen) {
|
||||
return -1;
|
||||
} else if (aLen > bLen) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function compareIgnoreCase(a: string, b: string): number {
|
||||
return compareSubstringIgnoreCase(a, b, 0, a.length, 0, b.length);
|
||||
}
|
||||
|
||||
export function compareSubstringIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
|
||||
|
||||
for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
|
||||
|
||||
@@ -307,26 +331,20 @@ export function compareIgnoreCase(a: string, b: string, aStart: number = 0, aEnd
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isUpperAsciiLetter(codeA)) {
|
||||
codeA += 32;
|
||||
}
|
||||
|
||||
if (isUpperAsciiLetter(codeB)) {
|
||||
codeB += 32;
|
||||
}
|
||||
|
||||
const diff = codeA - codeB;
|
||||
|
||||
if (diff === 0) {
|
||||
// equal -> ignoreCase
|
||||
if (diff === 32 && isUpperAsciiLetter(codeB)) { //codeB =[65-90] && codeA =[97-122]
|
||||
continue;
|
||||
|
||||
} else if (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {
|
||||
} else if (diff === -32 && isUpperAsciiLetter(codeA)) { //codeB =[97-122] && codeA =[65-90]
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {
|
||||
//
|
||||
return diff;
|
||||
|
||||
} else {
|
||||
return compare(a.toLowerCase(), b.toLowerCase());
|
||||
return compareSubstring(a.toLowerCase(), b.toLowerCase(), aStart, aEnd, bStart, bEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,6 +851,9 @@ export function safeBtoa(str: string): string {
|
||||
return btoa(encodeURIComponent(str)); // we use encodeURIComponent because btoa fails for non Latin 1 values
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated ES6
|
||||
*/
|
||||
export function repeat(s: string, count: number): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < count; i++) {
|
||||
|
||||
@@ -258,3 +258,19 @@ export type Dto<T> = { [K in keyof T]: T[K] extends URI
|
||||
: T[K] extends Function
|
||||
? never
|
||||
: UriDto<T[K]> };
|
||||
|
||||
|
||||
export function NotImplementedProxy<T>(name: string): { new(): T } {
|
||||
return <any>class {
|
||||
constructor() {
|
||||
return new Proxy({}, {
|
||||
get(target: any, prop: PropertyKey) {
|
||||
if (target[prop]) {
|
||||
return target[prop];
|
||||
}
|
||||
throw new Error(`Not Implemented: ${name}->${String(prop)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,10 +138,6 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
|
||||
});
|
||||
}
|
||||
|
||||
export function decode(buffer: Buffer, encoding: string): string {
|
||||
return iconv.decode(buffer, toNodeEncoding(encoding));
|
||||
}
|
||||
|
||||
export function encodingExists(encoding: string): boolean {
|
||||
return iconv.encodingExists(toNodeEncoding(encoding));
|
||||
}
|
||||
@@ -154,7 +150,7 @@ export function encodeStream(encoding: string, options?: { addBOM?: boolean }):
|
||||
return iconv.encodeStream(toNodeEncoding(encoding), options);
|
||||
}
|
||||
|
||||
function toNodeEncoding(enc: string | null): string {
|
||||
export function toNodeEncoding(enc: string | null): string {
|
||||
if (enc === UTF8_with_bom || enc === null) {
|
||||
return UTF8; // iconv does not distinguish UTF 8 with or without BOM, so we need to help it
|
||||
}
|
||||
|
||||
@@ -109,8 +109,11 @@
|
||||
|
||||
.quick-input-action .monaco-text-button {
|
||||
font-size: 85%;
|
||||
padding: 7px 6px 5.5px 6px;
|
||||
padding: 0 6px;
|
||||
line-height: initial;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quick-input-message {
|
||||
@@ -202,7 +205,6 @@
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-rows > .quick-input-list-row .codicon[class*='codicon-'] {
|
||||
color: currentColor !important;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/lis
|
||||
import { List, IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { registerIcon, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IQuickInputOptions {
|
||||
idPrefix: string;
|
||||
@@ -67,8 +68,11 @@ const $ = dom.$;
|
||||
|
||||
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
||||
|
||||
|
||||
const backButtonIcon = registerIcon('quick-input-back', Codicon.arrowLeft);
|
||||
|
||||
const backButton = {
|
||||
iconClass: 'codicon-arrow-left',
|
||||
iconClass: backButtonIcon.classNames,
|
||||
tooltip: localize('quickInput.back', "Back"),
|
||||
handle: -1 // TODO
|
||||
};
|
||||
@@ -662,14 +666,14 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.ui.list.clearFocus();
|
||||
}
|
||||
}));
|
||||
this.visibleDisposables.add(this.ui.inputBox.onKeyDown(event => {
|
||||
this.visibleDisposables.add((this._hideInput ? this.ui.list : this.ui.inputBox).onKeyDown((event: KeyboardEvent | StandardKeyboardEvent) => {
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.DownArrow:
|
||||
this.ui.list.focus(QuickInputListFocus.Next);
|
||||
if (this.canSelectMany) {
|
||||
this.ui.list.domFocus();
|
||||
}
|
||||
event.preventDefault();
|
||||
dom.EventHelper.stop(event, true);
|
||||
break;
|
||||
case KeyCode.UpArrow:
|
||||
if (this.ui.list.getFocusedElements().length) {
|
||||
@@ -680,21 +684,21 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
if (this.canSelectMany) {
|
||||
this.ui.list.domFocus();
|
||||
}
|
||||
event.preventDefault();
|
||||
dom.EventHelper.stop(event, true);
|
||||
break;
|
||||
case KeyCode.PageDown:
|
||||
this.ui.list.focus(QuickInputListFocus.NextPage);
|
||||
if (this.canSelectMany) {
|
||||
this.ui.list.domFocus();
|
||||
}
|
||||
event.preventDefault();
|
||||
dom.EventHelper.stop(event, true);
|
||||
break;
|
||||
case KeyCode.PageUp:
|
||||
this.ui.list.focus(QuickInputListFocus.PreviousPage);
|
||||
if (this.canSelectMany) {
|
||||
this.ui.list.domFocus();
|
||||
}
|
||||
event.preventDefault();
|
||||
dom.EventHelper.stop(event, true);
|
||||
break;
|
||||
case KeyCode.RightArrow:
|
||||
if (!this._canAcceptInBackground) {
|
||||
@@ -711,6 +715,18 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.onDidAcceptEmitter.fire({ inBackground: true });
|
||||
}
|
||||
|
||||
break;
|
||||
case KeyCode.Home:
|
||||
if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
|
||||
this.ui.list.focus(QuickInputListFocus.First);
|
||||
dom.EventHelper.stop(event, true);
|
||||
}
|
||||
break;
|
||||
case KeyCode.End:
|
||||
if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
|
||||
this.ui.list.focus(QuickInputListFocus.Last);
|
||||
dom.EventHelper.stop(event, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}));
|
||||
@@ -1077,10 +1093,10 @@ export class QuickInputController extends Disposable {
|
||||
private parentElement: HTMLElement;
|
||||
private styles: IQuickInputStyles;
|
||||
|
||||
private onShowEmitter = new Emitter<void>();
|
||||
private onShowEmitter = this._register(new Emitter<void>());
|
||||
readonly onShow = this.onShowEmitter.event;
|
||||
|
||||
private onHideEmitter = new Emitter<void>();
|
||||
private onHideEmitter = this._register(new Emitter<void>());
|
||||
readonly onHide = this.onHideEmitter.event;
|
||||
|
||||
private previousFocusElement?: HTMLElement;
|
||||
@@ -1287,9 +1303,10 @@ export class QuickInputController extends Disposable {
|
||||
return this.ui;
|
||||
}
|
||||
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): Promise<O extends { canPickMany: true } ? T[] : T> {
|
||||
return new Promise<O extends { canPickMany: true } ? T[] : T>((doResolve, reject) => {
|
||||
let resolve = (result: any) => {
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {
|
||||
type R = (O extends { canPickMany: true } ? T[] : T) | undefined;
|
||||
return new Promise<R>((doResolve, reject) => {
|
||||
let resolve = (result: R) => {
|
||||
resolve = doResolve;
|
||||
if (options.onKeyMods) {
|
||||
options.onKeyMods(input.keyMods);
|
||||
@@ -1306,12 +1323,12 @@ export class QuickInputController extends Disposable {
|
||||
input,
|
||||
input.onDidAccept(() => {
|
||||
if (input.canSelectMany) {
|
||||
resolve(<any>input.selectedItems.slice());
|
||||
resolve(<R>input.selectedItems.slice());
|
||||
input.hide();
|
||||
} else {
|
||||
const result = input.activeItems[0];
|
||||
if (result) {
|
||||
resolve(<any>result);
|
||||
resolve(<R>result);
|
||||
input.hide();
|
||||
}
|
||||
}
|
||||
@@ -1326,7 +1343,7 @@ export class QuickInputController extends Disposable {
|
||||
if (!input.canSelectMany) {
|
||||
const result = items[0];
|
||||
if (result) {
|
||||
resolve(<any>result);
|
||||
resolve(<R>result);
|
||||
input.hide();
|
||||
}
|
||||
}
|
||||
@@ -1388,7 +1405,7 @@ export class QuickInputController extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
input(options: IInputOptions = {}, token: CancellationToken = CancellationToken.None): Promise<string> {
|
||||
input(options: IInputOptions = {}, token: CancellationToken = CancellationToken.None): Promise<string | undefined> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(undefined);
|
||||
|
||||
@@ -25,8 +25,9 @@ import { Action } from 'vs/base/common/actions';
|
||||
import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput';
|
||||
import { IListOptions, List, IListStyles, IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListOptions, List, IListStyles, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -45,7 +46,7 @@ interface IListElement {
|
||||
readonly fireButtonTriggered: (event: IQuickPickItemButtonEvent<IQuickPickItem>) => void;
|
||||
}
|
||||
|
||||
class ListElement implements IListElement {
|
||||
class ListElement implements IListElement, IDisposable {
|
||||
index!: number;
|
||||
item!: IQuickPickItem;
|
||||
saneLabel!: string;
|
||||
@@ -74,6 +75,10 @@ class ListElement implements IListElement {
|
||||
constructor(init: IListElement) {
|
||||
assign(this, init);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._onChecked.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
interface IListElementTemplateData {
|
||||
@@ -259,6 +264,8 @@ export class QuickInputList {
|
||||
onChangedCheckedElements: Event<IQuickPickItem[]> = this._onChangedCheckedElements.event;
|
||||
private readonly _onButtonTriggered = new Emitter<IQuickPickItemButtonEvent<IQuickPickItem>>();
|
||||
onButtonTriggered = this._onButtonTriggered.event;
|
||||
private readonly _onKeyDown = new Emitter<StandardKeyboardEvent>();
|
||||
onKeyDown: Event<StandardKeyboardEvent> = this._onKeyDown.event;
|
||||
private readonly _onLeave = new Emitter<void>();
|
||||
onLeave: Event<void> = this._onLeave.event;
|
||||
private _fireCheckedEvents = true;
|
||||
@@ -280,13 +287,7 @@ export class QuickInputList {
|
||||
setRowLineHeight: false,
|
||||
multipleSelectionSupport: false,
|
||||
horizontalScrolling: false,
|
||||
accessibilityProvider,
|
||||
ariaProvider: {
|
||||
getRole: () => 'option',
|
||||
getSetSize: (_: ListElement, _index: number, listLength: number) => listLength,
|
||||
getPosInSet: (_: ListElement, index: number) => index
|
||||
},
|
||||
ariaRole: 'listbox'
|
||||
accessibilityProvider
|
||||
} as IListOptions<ListElement>);
|
||||
this.list.getHTMLElement().id = id;
|
||||
this.disposables.push(this.list);
|
||||
@@ -314,6 +315,8 @@ export class QuickInputList {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this._onKeyDown.fire(event);
|
||||
}));
|
||||
this.disposables.push(this.list.onMouseDown(e => {
|
||||
if (e.browserEvent.button !== 2) {
|
||||
@@ -341,6 +344,15 @@ export class QuickInputList {
|
||||
this.list.setSelection([e.index]);
|
||||
}
|
||||
}));
|
||||
this.disposables.push(
|
||||
this._onChangedAllVisibleChecked,
|
||||
this._onChangedCheckedCount,
|
||||
this._onChangedVisibleCount,
|
||||
this._onChangedCheckedElements,
|
||||
this._onButtonTriggered,
|
||||
this._onLeave,
|
||||
this._onKeyDown
|
||||
);
|
||||
}
|
||||
|
||||
@memoize
|
||||
@@ -439,6 +451,7 @@ export class QuickInputList {
|
||||
}
|
||||
return result;
|
||||
}, [] as ListElement[]);
|
||||
this.elementDisposables.push(...this.elements);
|
||||
this.elementDisposables.push(...this.elements.map(element => element.onChecked(() => this.fireCheckedEvents())));
|
||||
|
||||
this.elementsToIndexes = this.elements.reduce((map, element, index) => {
|
||||
@@ -699,8 +712,21 @@ function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: s
|
||||
return compareAnything(elementA.saneLabel, elementB.saneLabel, lookFor);
|
||||
}
|
||||
|
||||
class QuickInputAccessibilityProvider implements IAccessibilityProvider<ListElement> {
|
||||
class QuickInputAccessibilityProvider implements IListAccessibilityProvider<ListElement> {
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return localize('quickInput', "Quick Input");
|
||||
}
|
||||
|
||||
getAriaLabel(element: ListElement): string | null {
|
||||
return element.saneAriaLabel;
|
||||
}
|
||||
|
||||
getWidgetRole() {
|
||||
return 'listbox';
|
||||
}
|
||||
|
||||
getRole() {
|
||||
return 'option';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as assert from 'assert';
|
||||
import * as scorer from 'vs/base/common/fuzzyScorer';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { basename, dirname, sep } from 'vs/base/common/path';
|
||||
import { basename, dirname, sep, posix, win32 } from 'vs/base/common/path';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
@@ -27,6 +27,40 @@ class ResourceAccessorClass implements scorer.IItemAccessor<URI> {
|
||||
|
||||
const ResourceAccessor = new ResourceAccessorClass();
|
||||
|
||||
class ResourceWithSlashAccessorClass implements scorer.IItemAccessor<URI> {
|
||||
|
||||
getItemLabel(resource: URI): string {
|
||||
return basename(resource.fsPath);
|
||||
}
|
||||
|
||||
getItemDescription(resource: URI): string {
|
||||
return posix.normalize(dirname(resource.path));
|
||||
}
|
||||
|
||||
getItemPath(resource: URI): string {
|
||||
return posix.normalize(resource.path);
|
||||
}
|
||||
}
|
||||
|
||||
const ResourceWithSlashAccessor = new ResourceWithSlashAccessorClass();
|
||||
|
||||
class ResourceWithBackslashAccessorClass implements scorer.IItemAccessor<URI> {
|
||||
|
||||
getItemLabel(resource: URI): string {
|
||||
return basename(resource.fsPath);
|
||||
}
|
||||
|
||||
getItemDescription(resource: URI): string {
|
||||
return win32.normalize(dirname(resource.path));
|
||||
}
|
||||
|
||||
getItemPath(resource: URI): string {
|
||||
return win32.normalize(resource.path);
|
||||
}
|
||||
}
|
||||
|
||||
const ResourceWithBackslashAccessor = new ResourceWithBackslashAccessorClass();
|
||||
|
||||
class NullAccessorClass implements scorer.IItemAccessor<URI> {
|
||||
|
||||
getItemLabel(resource: URI): string {
|
||||
@@ -48,29 +82,24 @@ function _doScore(target: string, query: string, fuzzy: boolean): scorer.FuzzySc
|
||||
return scorer.scoreFuzzy(target, preparedQuery.normalized, preparedQuery.normalizedLowercase, fuzzy);
|
||||
}
|
||||
|
||||
function _doScore2(target: string, query: string): scorer.FuzzyScore2 {
|
||||
function _doScore2(target: string, query: string, matchOffset: number = 0): scorer.FuzzyScore2 {
|
||||
const preparedQuery = scorer.prepareQuery(query);
|
||||
|
||||
return scorer.scoreFuzzy2(target, preparedQuery);
|
||||
return scorer.scoreFuzzy2(target, preparedQuery, 0, matchOffset);
|
||||
}
|
||||
|
||||
function scoreItem<T>(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.FuzzyScorerCache): scorer.IItemScore {
|
||||
return scorer.scoreItemFuzzy(item, scorer.prepareQuery(query), fuzzy, accessor, cache);
|
||||
function scoreItem<T>(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>): scorer.IItemScore {
|
||||
return scorer.scoreItemFuzzy(item, scorer.prepareQuery(query), fuzzy, accessor, Object.create(null));
|
||||
}
|
||||
|
||||
function compareItemsByScore<T>(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.FuzzyScorerCache): number {
|
||||
return scorer.compareItemsByFuzzyScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, cache);
|
||||
function compareItemsByScore<T>(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>): number {
|
||||
return scorer.compareItemsByFuzzyScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, Object.create(null));
|
||||
}
|
||||
|
||||
const NullAccessor = new NullAccessorClass();
|
||||
let cache: scorer.FuzzyScorerCache = Object.create(null);
|
||||
|
||||
suite('Fuzzy Scorer', () => {
|
||||
|
||||
setup(() => {
|
||||
cache = Object.create(null);
|
||||
});
|
||||
|
||||
test('score (fuzzy)', function () {
|
||||
const target = 'HeLlo-World';
|
||||
|
||||
@@ -118,16 +147,16 @@ suite('Fuzzy Scorer', () => {
|
||||
});
|
||||
|
||||
test('scoreItem - matches are proper', function () {
|
||||
let res = scoreItem(null, 'something', true, ResourceAccessor, cache);
|
||||
let res = scoreItem(null, 'something', true, ResourceAccessor);
|
||||
assert.ok(!res.score);
|
||||
|
||||
const resource = URI.file('/xyz/some/path/someFile123.txt');
|
||||
|
||||
res = scoreItem(resource, 'something', true, NullAccessor, cache);
|
||||
res = scoreItem(resource, 'something', true, NullAccessor);
|
||||
assert.ok(!res.score);
|
||||
|
||||
// Path Identity
|
||||
const identityRes = scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor, cache);
|
||||
const identityRes = scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor);
|
||||
assert.ok(identityRes.score);
|
||||
assert.equal(identityRes.descriptionMatch!.length, 1);
|
||||
assert.equal(identityRes.labelMatch!.length, 1);
|
||||
@@ -137,7 +166,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(identityRes.labelMatch![0].end, ResourceAccessor.getItemLabel(resource).length);
|
||||
|
||||
// Basename Prefix
|
||||
const basenamePrefixRes = scoreItem(resource, 'som', true, ResourceAccessor, cache);
|
||||
const basenamePrefixRes = scoreItem(resource, 'som', true, ResourceAccessor);
|
||||
assert.ok(basenamePrefixRes.score);
|
||||
assert.ok(!basenamePrefixRes.descriptionMatch);
|
||||
assert.equal(basenamePrefixRes.labelMatch!.length, 1);
|
||||
@@ -145,7 +174,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(basenamePrefixRes.labelMatch![0].end, 'som'.length);
|
||||
|
||||
// Basename Camelcase
|
||||
const basenameCamelcaseRes = scoreItem(resource, 'sF', true, ResourceAccessor, cache);
|
||||
const basenameCamelcaseRes = scoreItem(resource, 'sF', true, ResourceAccessor);
|
||||
assert.ok(basenameCamelcaseRes.score);
|
||||
assert.ok(!basenameCamelcaseRes.descriptionMatch);
|
||||
assert.equal(basenameCamelcaseRes.labelMatch!.length, 2);
|
||||
@@ -155,7 +184,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(basenameCamelcaseRes.labelMatch![1].end, 5);
|
||||
|
||||
// Basename Match
|
||||
const basenameRes = scoreItem(resource, 'of', true, ResourceAccessor, cache);
|
||||
const basenameRes = scoreItem(resource, 'of', true, ResourceAccessor);
|
||||
assert.ok(basenameRes.score);
|
||||
assert.ok(!basenameRes.descriptionMatch);
|
||||
assert.equal(basenameRes.labelMatch!.length, 2);
|
||||
@@ -165,7 +194,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(basenameRes.labelMatch![1].end, 5);
|
||||
|
||||
// Path Match
|
||||
const pathRes = scoreItem(resource, 'xyz123', true, ResourceAccessor, cache);
|
||||
const pathRes = scoreItem(resource, 'xyz123', true, ResourceAccessor);
|
||||
assert.ok(pathRes.score);
|
||||
assert.ok(pathRes.descriptionMatch);
|
||||
assert.ok(pathRes.labelMatch);
|
||||
@@ -177,7 +206,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(pathRes.descriptionMatch![0].end, 4);
|
||||
|
||||
// No Match
|
||||
const noRes = scoreItem(resource, '987', true, ResourceAccessor, cache);
|
||||
const noRes = scoreItem(resource, '987', true, ResourceAccessor);
|
||||
assert.ok(!noRes.score);
|
||||
assert.ok(!noRes.labelMatch);
|
||||
assert.ok(!noRes.descriptionMatch);
|
||||
@@ -192,7 +221,7 @@ suite('Fuzzy Scorer', () => {
|
||||
test('scoreItem - multiple', function () {
|
||||
const resource = URI.file('/xyz/some/path/someFile123.txt');
|
||||
|
||||
let res1 = scoreItem(resource, 'xyz some', true, ResourceAccessor, cache);
|
||||
let res1 = scoreItem(resource, 'xyz some', true, ResourceAccessor);
|
||||
assert.ok(res1.score);
|
||||
assert.equal(res1.labelMatch?.length, 1);
|
||||
assert.equal(res1.labelMatch![0].start, 0);
|
||||
@@ -201,7 +230,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(res1.descriptionMatch![0].start, 1);
|
||||
assert.equal(res1.descriptionMatch![0].end, 4);
|
||||
|
||||
let res2 = scoreItem(resource, 'some xyz', true, ResourceAccessor, cache);
|
||||
let res2 = scoreItem(resource, 'some xyz', true, ResourceAccessor);
|
||||
assert.ok(res2.score);
|
||||
assert.equal(res1.score, res2.score);
|
||||
assert.equal(res2.labelMatch?.length, 1);
|
||||
@@ -211,7 +240,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(res2.descriptionMatch![0].start, 1);
|
||||
assert.equal(res2.descriptionMatch![0].end, 4);
|
||||
|
||||
let res3 = scoreItem(resource, 'some xyz file file123', true, ResourceAccessor, cache);
|
||||
let res3 = scoreItem(resource, 'some xyz file file123', true, ResourceAccessor);
|
||||
assert.ok(res3.score);
|
||||
assert.ok(res3.score > res2.score);
|
||||
assert.equal(res3.labelMatch?.length, 1);
|
||||
@@ -221,7 +250,7 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(res3.descriptionMatch![0].start, 1);
|
||||
assert.equal(res3.descriptionMatch![0].end, 4);
|
||||
|
||||
let res4 = scoreItem(resource, 'path z y', true, ResourceAccessor, cache);
|
||||
let res4 = scoreItem(resource, 'path z y', true, ResourceAccessor);
|
||||
assert.ok(res4.score);
|
||||
assert.ok(res4.score < res2.score);
|
||||
assert.equal(res4.labelMatch?.length, 0);
|
||||
@@ -234,10 +263,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
test('scoreItem - invalid input', function () {
|
||||
|
||||
let res = scoreItem(null, null!, true, ResourceAccessor, cache);
|
||||
let res = scoreItem(null, null!, true, ResourceAccessor);
|
||||
assert.equal(res.score, 0);
|
||||
|
||||
res = scoreItem(null, 'null', true, ResourceAccessor, cache);
|
||||
res = scoreItem(null, 'null', true, ResourceAccessor);
|
||||
assert.equal(res.score, 0);
|
||||
});
|
||||
|
||||
@@ -247,7 +276,7 @@ suite('Fuzzy Scorer', () => {
|
||||
// xsp is more relevant to the end of the file path even though it matches
|
||||
// fuzzy also in the beginning. we verify the more relevant match at the
|
||||
// end gets returned.
|
||||
const pathRes = scoreItem(resource, 'xspfile123', true, ResourceAccessor, cache);
|
||||
const pathRes = scoreItem(resource, 'xspfile123', true, ResourceAccessor);
|
||||
assert.ok(pathRes.score);
|
||||
assert.ok(pathRes.descriptionMatch);
|
||||
assert.ok(pathRes.labelMatch);
|
||||
@@ -262,7 +291,7 @@ suite('Fuzzy Scorer', () => {
|
||||
test('scoreItem - avoid match scattering (bug #36119)', function () {
|
||||
const resource = URI.file('projects/ui/cula/ats/target.mk');
|
||||
|
||||
const pathRes = scoreItem(resource, 'tcltarget.mk', true, ResourceAccessor, cache);
|
||||
const pathRes = scoreItem(resource, 'tcltarget.mk', true, ResourceAccessor);
|
||||
assert.ok(pathRes.score);
|
||||
assert.ok(pathRes.descriptionMatch);
|
||||
assert.ok(pathRes.labelMatch);
|
||||
@@ -276,7 +305,7 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
// expect "ad" to be matched towards the end of the file because the
|
||||
// match is more compact
|
||||
const res = scoreItem(resource, 'ad', true, ResourceAccessor, cache);
|
||||
const res = scoreItem(resource, 'ad', true, ResourceAccessor);
|
||||
assert.ok(res.score);
|
||||
assert.ok(res.descriptionMatch);
|
||||
assert.ok(!res.labelMatch!.length);
|
||||
@@ -290,14 +319,14 @@ suite('Fuzzy Scorer', () => {
|
||||
test('scoreItem - proper target offset', function () {
|
||||
const resource = URI.file('etem');
|
||||
|
||||
const res = scoreItem(resource, 'teem', true, ResourceAccessor, cache);
|
||||
const res = scoreItem(resource, 'teem', true, ResourceAccessor);
|
||||
assert.ok(!res.score);
|
||||
});
|
||||
|
||||
test('scoreItem - proper target offset #2', function () {
|
||||
const resource = URI.file('ede');
|
||||
|
||||
const res = scoreItem(resource, 'de', true, ResourceAccessor, cache);
|
||||
const res = scoreItem(resource, 'de', true, ResourceAccessor);
|
||||
|
||||
assert.equal(res.labelMatch!.length, 1);
|
||||
assert.equal(res.labelMatch![0].start, 1);
|
||||
@@ -307,7 +336,7 @@ suite('Fuzzy Scorer', () => {
|
||||
test('scoreItem - proper target offset #3', function () {
|
||||
const resource = URI.file('/src/vs/editor/browser/viewParts/lineNumbers/flipped-cursor-2x.svg');
|
||||
|
||||
const res = scoreItem(resource, 'debug', true, ResourceAccessor, cache);
|
||||
const res = scoreItem(resource, 'debug', true, ResourceAccessor);
|
||||
|
||||
assert.equal(res.descriptionMatch!.length, 3);
|
||||
assert.equal(res.descriptionMatch![0].start, 9);
|
||||
@@ -327,7 +356,7 @@ suite('Fuzzy Scorer', () => {
|
||||
test('scoreItem - no match unless query contained in sequence', function () {
|
||||
const resource = URI.file('abcde');
|
||||
|
||||
const res = scoreItem(resource, 'edcda', true, ResourceAccessor, cache);
|
||||
const res = scoreItem(resource, 'edcda', true, ResourceAccessor);
|
||||
assert.ok(!res.score);
|
||||
});
|
||||
|
||||
@@ -336,10 +365,22 @@ suite('Fuzzy Scorer', () => {
|
||||
const remoteResource = URI.from({ scheme: Schemas.vscodeRemote, path: 'abcde/super/duper' });
|
||||
|
||||
for (const resource of [localResource, remoteResource]) {
|
||||
let res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceAccessor, cache);
|
||||
let res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceAccessor);
|
||||
assert.ok(res.score);
|
||||
|
||||
res = scoreItem(resource, 'abcde/super/duper', true, ResourceAccessor, cache);
|
||||
res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceWithSlashAccessor);
|
||||
assert.ok(res.score);
|
||||
|
||||
res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceWithBackslashAccessor);
|
||||
assert.ok(res.score);
|
||||
|
||||
res = scoreItem(resource, 'abcde/super/duper', true, ResourceAccessor);
|
||||
assert.ok(res.score);
|
||||
|
||||
res = scoreItem(resource, 'abcde/super/duper', true, ResourceWithSlashAccessor);
|
||||
assert.ok(res.score);
|
||||
|
||||
res = scoreItem(resource, 'abcde/super/duper', true, ResourceWithBackslashAccessor);
|
||||
assert.ok(res.score);
|
||||
}
|
||||
});
|
||||
@@ -352,12 +393,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Full resource A path
|
||||
let query = ResourceAccessor.getItemPath(resourceA);
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -365,12 +406,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Full resource B path
|
||||
query = ResourceAccessor.getItemPath(resourceB);
|
||||
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -384,12 +425,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Full resource A basename
|
||||
let query = ResourceAccessor.getItemLabel(resourceA);
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -397,12 +438,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Full resource B basename
|
||||
query = ResourceAccessor.getItemLabel(resourceB);
|
||||
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -416,12 +457,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// resource A camelcase
|
||||
let query = 'fA';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -429,12 +470,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// resource B camelcase
|
||||
query = 'fB';
|
||||
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -448,12 +489,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource A part of basename
|
||||
let query = 'fileA';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -461,12 +502,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource B part of basename
|
||||
query = 'fileB';
|
||||
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -480,12 +521,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource A part of path
|
||||
let query = 'pathfileA';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -493,12 +534,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource B part of path
|
||||
query = 'pathfileB';
|
||||
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -512,12 +553,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource A part of path
|
||||
let query = 'somepath';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -531,12 +572,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource A part of path
|
||||
let query = 'file';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceC);
|
||||
assert.equal(res[2], resourceB);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceC);
|
||||
assert.equal(res[2], resourceB);
|
||||
@@ -550,12 +591,12 @@ suite('Fuzzy Scorer', () => {
|
||||
// Resource A part of path
|
||||
let query = 'somepath';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceB);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -568,7 +609,7 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'co/te';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
assert.equal(res[2], resourceC);
|
||||
@@ -580,7 +621,7 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'partsquick';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
});
|
||||
@@ -591,11 +632,11 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'AH';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
});
|
||||
@@ -606,11 +647,11 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'xp';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
});
|
||||
@@ -621,11 +662,11 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'xp';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
});
|
||||
@@ -636,11 +677,11 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'exfile';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
});
|
||||
@@ -653,18 +694,18 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = isWindows ? 'modu1\\index.js' : 'modu1/index.js';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
|
||||
query = isWindows ? 'un1\\index.js' : 'un1/index.js';
|
||||
|
||||
res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -675,10 +716,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'StatVideoindex';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
});
|
||||
|
||||
@@ -688,10 +729,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'reproreduxts';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -702,10 +743,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'bookpageIndex';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceC);
|
||||
});
|
||||
|
||||
@@ -715,10 +756,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = isWindows ? 'ui\\icons' : 'ui/icons';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -728,10 +769,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = isWindows ? 'ui\\input\\index' : 'ui/input/index';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -741,10 +782,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'djancosig';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -755,12 +796,12 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'protectedconfig.php';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceC);
|
||||
assert.equal(res[2], resourceB);
|
||||
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceA);
|
||||
assert.equal(res[1], resourceC);
|
||||
assert.equal(res[2], resourceB);
|
||||
@@ -772,10 +813,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'gradientmain';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -785,10 +826,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'abc';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -798,10 +839,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'xyz';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -811,10 +852,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'async';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -824,10 +865,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'partisettings';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -837,10 +878,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'tipsindex.cshtml';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -850,10 +891,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'listview';
|
||||
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -864,10 +905,10 @@ suite('Fuzzy Scorer', () => {
|
||||
|
||||
let query = 'filesexplorerview.ts';
|
||||
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
|
||||
res = [resourceA, resourceC, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache));
|
||||
res = [resourceA, resourceC, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
@@ -932,6 +973,28 @@ suite('Fuzzy Scorer', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('fuzzyScore2 (matching)', function () {
|
||||
const target = 'HeLlo-World';
|
||||
|
||||
for (const offset of [0, 3]) {
|
||||
let [score, matches] = _doScore2(target, 'HeLlo-World', offset);
|
||||
|
||||
assert.ok(score);
|
||||
assert.equal(matches.length, 1);
|
||||
assert.equal(matches[0].start, 0 + offset);
|
||||
assert.equal(matches[0].end, target.length + offset);
|
||||
|
||||
[score, matches] = _doScore2(target, 'HW', offset);
|
||||
|
||||
assert.ok(score);
|
||||
assert.equal(matches.length, 2);
|
||||
assert.equal(matches[0].start, 0 + offset);
|
||||
assert.equal(matches[0].end, 1 + offset);
|
||||
assert.equal(matches[1].start, 6 + offset);
|
||||
assert.equal(matches[1].end, 7 + offset);
|
||||
}
|
||||
});
|
||||
|
||||
test('fuzzyScore2 (multiple queries)', function () {
|
||||
const target = 'HeLlo-World';
|
||||
|
||||
@@ -957,7 +1020,7 @@ suite('Fuzzy Scorer', () => {
|
||||
}
|
||||
|
||||
function assertNoScore() {
|
||||
assert.equal(multiScore, 0);
|
||||
assert.equal(multiScore, undefined);
|
||||
assert.equal(multiMatches.length, 0);
|
||||
}
|
||||
|
||||
@@ -975,4 +1038,13 @@ suite('Fuzzy Scorer', () => {
|
||||
[multiScore, multiMatches] = _doScore2(target, 'More Nothing');
|
||||
assertNoScore();
|
||||
});
|
||||
|
||||
test('fuzzyScore2 (#95716)', function () {
|
||||
const target = '# ❌ Wow';
|
||||
|
||||
const score = _doScore2(target, '❌');
|
||||
assert.ok(score);
|
||||
assert.ok(typeof score[0] === 'number');
|
||||
assert.ok(score[1].length > 0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ suite('Strings', () => {
|
||||
test('compareIgnoreCase (substring)', () => {
|
||||
|
||||
function assertCompareIgnoreCase(a: string, b: string, aStart: number, aEnd: number, bStart: number, bEnd: number, recurse = true): void {
|
||||
let actual = strings.compareIgnoreCase(a, b, aStart, aEnd, bStart, bEnd);
|
||||
let actual = strings.compareSubstringIgnoreCase(a, b, aStart, aEnd, bStart, bEnd);
|
||||
actual = actual > 0 ? 1 : actual < 0 ? -1 : actual;
|
||||
|
||||
let expected = strings.compare(a.toLowerCase().substring(aStart, aEnd), b.toLowerCase().substring(bStart, bEnd));
|
||||
|
||||
@@ -8,6 +8,7 @@ import * as fs from 'fs';
|
||||
import * as encoding from 'vs/base/node/encoding';
|
||||
import * as terminalEncoding from 'vs/base/node/terminalEncoding';
|
||||
import { Readable } from 'stream';
|
||||
import * as iconv from 'iconv-lite';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
|
||||
export async function detectEncodingByBOM(file: string): Promise<typeof encoding.UTF16be | typeof encoding.UTF16le | typeof encoding.UTF8_with_bom | null> {
|
||||
@@ -224,7 +225,7 @@ suite('Encoding', () => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(encoding.decode(data, fileEncoding!));
|
||||
resolve(iconv.decode(data, encoding.toNodeEncoding(fileEncoding!)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,8 @@ import * as os from 'os';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { CodiconLabel } from 'vs/base/browser/ui/codiconLabel/codiconLabel';
|
||||
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
|
||||
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -715,7 +716,7 @@ export class IssueReporter extends Disposable {
|
||||
type IssueReporterSearchError = {
|
||||
message: string;
|
||||
};
|
||||
this.telemetryService.publicLog2<IssueReporterSearchError, IssueReporterSearchErrorClassification>('issueReporterSearchError', { message: error.message });
|
||||
this.telemetryService.publicLog2<IssueReporterSearchError, IssueReporterSearchErrorClassification>('issueReporterSearchError', { message: error.message }, true);
|
||||
}
|
||||
|
||||
private setUpTypes(): void {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
@@ -66,8 +68,8 @@
|
||||
<section id="main">
|
||||
<p id="message"></p>
|
||||
<form id="form">
|
||||
<p><input type="text" id="username" placeholder="Username" required/></p>
|
||||
<p><input type="password" id="password" placeholder="Password" required/></p>
|
||||
<p><input type="text" id="username" placeholder="Username" required /></p>
|
||||
<p><input type="password" id="password" placeholder="Password" required /></p>
|
||||
<p id="buttons">
|
||||
<input id="ok" type="submit" value="OK" />
|
||||
<input id="cancel" type="button" value="Cancel" />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent, BrowserWindow } from 'electron';
|
||||
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent, BrowserWindow, dialog, session } from 'electron';
|
||||
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { WindowsMainService } from 'vs/platform/windows/electron-main/windowsMainService';
|
||||
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
@@ -80,6 +80,7 @@ import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { StorageKeysSyncRegistryChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
|
||||
export class CodeApplication extends Disposable {
|
||||
private windowsMainService: IWindowsMainService | undefined;
|
||||
@@ -128,7 +129,7 @@ export class CodeApplication extends Disposable {
|
||||
}
|
||||
});
|
||||
|
||||
// Security related measures (https://electronjs.org/docs/tutorial/security)
|
||||
//#region Security related measures (https://electronjs.org/docs/tutorial/security)
|
||||
//
|
||||
// !!! DO NOT CHANGE without consulting the documentation !!!
|
||||
//
|
||||
@@ -211,8 +212,18 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
session.defaultSession.setPermissionRequestHandler((webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback) => {
|
||||
return callback(false);
|
||||
});
|
||||
|
||||
session.defaultSession.setPermissionCheckHandler((webContents, permission /* 'media' */) => {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
let macOpenFileURIs: IWindowOpenable[] = [];
|
||||
let runningTimeout: NodeJS.Timeout | null = null;
|
||||
app.on('open-file', (event: Event, path: string) => {
|
||||
@@ -605,6 +616,11 @@ export class CodeApplication extends Disposable {
|
||||
return undefined;
|
||||
}
|
||||
})).filter(pendingUriToHandle => {
|
||||
// if URI should be blocked, filter it out
|
||||
if (this.shouldBlockURI(pendingUriToHandle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter out any protocol link that wants to open as window so that
|
||||
// we open the right set of windows on startup and not restore the
|
||||
// previous workspace too.
|
||||
@@ -623,6 +639,10 @@ export class CodeApplication extends Disposable {
|
||||
const environmentService = this.environmentService;
|
||||
urlService.registerHandler({
|
||||
async handleURL(uri: URI): Promise<boolean> {
|
||||
// if URI should be blocked, behave as if it's handled
|
||||
if (app.shouldBlockURI(uri)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for URIs to open in window
|
||||
const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri);
|
||||
@@ -727,6 +747,29 @@ export class CodeApplication extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private shouldBlockURI(uri: URI): boolean {
|
||||
if (uri.authority === Schemas.file && isWindows) {
|
||||
const res = dialog.showMessageBoxSync({
|
||||
title: product.nameLong,
|
||||
type: 'question',
|
||||
buttons: [
|
||||
mnemonicButtonLabel(localize({ key: 'open', comment: ['&& denotes a mnemonic'] }, "&&Yes")),
|
||||
mnemonicButtonLabel(localize({ key: 'cancel', comment: ['&& denotes a mnemonic'] }, "&&No")),
|
||||
],
|
||||
cancelId: 1,
|
||||
message: localize('confirmOpenMessage', "An external application wants to open '{0}' in {1}. Do you want to open this file or folder?", getPathLabel(uri.fsPath), product.nameShort),
|
||||
detail: localize('confirmOpenDetail', "If you did not initiate this request, it may represent an attempted attack on your system. Unless you took an explicit action to initiate this request, you should press 'No'"),
|
||||
noLink: true
|
||||
});
|
||||
|
||||
if (res === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private getWindowOpenableFromProtocolLink(uri: URI): IWindowOpenable | undefined {
|
||||
if (!uri.path) {
|
||||
return undefined;
|
||||
|
||||
@@ -118,6 +118,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
private readonly touchBarGroups: TouchBarSegmentedControl[];
|
||||
|
||||
private currentHttpProxy?: string;
|
||||
private currentNoProxy?: string;
|
||||
|
||||
constructor(
|
||||
config: IWindowCreationOptions,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@@ -406,7 +409,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
|
||||
return callback({ cancel: false, responseHeaders });
|
||||
return callback({ cancel: false });
|
||||
});
|
||||
|
||||
// Remember that we loaded
|
||||
@@ -594,6 +597,24 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.currentMenuBarVisibility = newMenuBarVisibility;
|
||||
this.setMenuBarVisibility(newMenuBarVisibility);
|
||||
}
|
||||
// Do not set to empty configuration at startup if setting is empty to not override configuration through CLI options:
|
||||
const env = process.env;
|
||||
const newHttpProxy = (this.configurationService.getValue<string>('http.proxy') || '').trim()
|
||||
|| (env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY || '').trim() // Not standardized.
|
||||
|| undefined;
|
||||
const newNoProxy = (env.no_proxy || env.NO_PROXY || '').trim() || undefined; // Not standardized.
|
||||
if ((newHttpProxy || '').indexOf('@') === -1 && (newHttpProxy !== this.currentHttpProxy || newNoProxy !== this.currentNoProxy)) {
|
||||
this.currentHttpProxy = newHttpProxy;
|
||||
this.currentNoProxy = newNoProxy;
|
||||
const proxyRules = newHttpProxy || '';
|
||||
const proxyBypassRules = newNoProxy ? `${newNoProxy},<local>` : '<local>';
|
||||
this.logService.trace(`Setting proxy to '${proxyRules}', bypassing '${proxyBypassRules}'`);
|
||||
this._win.webContents.session.setProxy({
|
||||
proxyRules,
|
||||
proxyBypassRules,
|
||||
pacScript: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addTabbedWindow(window: ICodeWindow): void {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { TimeoutTimer } from 'vs/base/common/async';
|
||||
@@ -119,7 +118,7 @@ export class MouseHandler extends ViewEventHandler {
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { capture: true, passive: false }));
|
||||
this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { capture: true, passive: false }));
|
||||
|
||||
this._context.addEventHandler(this);
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ export class TextAreaHandler extends ViewPart {
|
||||
this.textArea.setAttribute('spellcheck', 'false');
|
||||
this.textArea.setAttribute('aria-label', this._getAriaLabel(options));
|
||||
this.textArea.setAttribute('role', 'textbox');
|
||||
this.textArea.setAttribute('aria-roledescription', nls.localize('editor', "editor"));
|
||||
this.textArea.setAttribute('aria-multiline', 'true');
|
||||
this.textArea.setAttribute('aria-haspopup', 'false');
|
||||
this.textArea.setAttribute('aria-autocomplete', 'both');
|
||||
|
||||
@@ -136,6 +136,8 @@ export class View extends ViewEventHandler {
|
||||
|
||||
this.domNode = createFastDomNode(document.createElement('div'));
|
||||
this.domNode.setClassName(this.getEditorClassName());
|
||||
// Set role 'code' for better screen reader support https://github.com/microsoft/vscode/issues/93438
|
||||
this.domNode.setAttribute('role', 'code');
|
||||
|
||||
this.overflowGuardContainer = createFastDomNode(document.createElement('div'));
|
||||
PartFingerprints.write(this.overflowGuardContainer, PartFingerprint.OverflowGuard);
|
||||
|
||||
@@ -49,6 +49,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
|
||||
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
|
||||
import { reverseLineChanges } from 'sql/editor/browser/diffEditorHelper';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
interface IEditorDiffDecorations {
|
||||
decorations: IModelDeltaDecoration[];
|
||||
@@ -159,6 +160,10 @@ class VisualEditorState {
|
||||
|
||||
let DIFF_EDITOR_ID = 0;
|
||||
|
||||
|
||||
const diffInsertIcon = registerIcon('diff-insert', Codicon.add);
|
||||
const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove);
|
||||
|
||||
export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor {
|
||||
|
||||
private static readonly ONE_OVERVIEW_WIDTH = 15;
|
||||
@@ -1630,7 +1635,7 @@ const DECORATIONS = {
|
||||
}),
|
||||
lineInsertWithSign: ModelDecorationOptions.register({
|
||||
className: 'line-insert',
|
||||
linesDecorationsClassName: 'insert-sign codicon codicon-add',
|
||||
linesDecorationsClassName: 'insert-sign ' + diffInsertIcon.classNames,
|
||||
marginClassName: 'line-insert',
|
||||
isWholeLine: true
|
||||
}),
|
||||
@@ -1642,7 +1647,7 @@ const DECORATIONS = {
|
||||
}),
|
||||
lineDeleteWithSign: ModelDecorationOptions.register({
|
||||
className: 'line-delete',
|
||||
linesDecorationsClassName: 'delete-sign codicon codicon-remove',
|
||||
linesDecorationsClassName: 'delete-sign ' + diffRemoveIcon.classNames,
|
||||
marginClassName: 'line-delete',
|
||||
isWholeLine: true
|
||||
|
||||
@@ -2101,7 +2106,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
||||
if (this.renderIndicators) {
|
||||
let index = lineNumber - lineChange.originalStartLineNumber;
|
||||
marginHTML = marginHTML.concat([
|
||||
`<div class="delete-sign codicon codicon-remove" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
|
||||
`<div class="delete-sign ${diffRemoveIcon.classNames}" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
|
||||
import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { registerIcon, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
const DIFF_LINES_PADDING = 3;
|
||||
|
||||
@@ -72,6 +73,10 @@ class Diff {
|
||||
}
|
||||
}
|
||||
|
||||
const diffReviewInsertIcon = registerIcon('diff-review-insert', Codicon.add);
|
||||
const diffReviewRemoveIcon = registerIcon('diff-review-remove', Codicon.remove);
|
||||
const diffReviewCloseIcon = registerIcon('diff-review-close', Codicon.close);
|
||||
|
||||
export class DiffReview extends Disposable {
|
||||
|
||||
private readonly _diffEditor: DiffEditorWidget;
|
||||
@@ -99,7 +104,7 @@ export class DiffReview extends Disposable {
|
||||
this.actionBarContainer.domNode
|
||||
));
|
||||
|
||||
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review codicon-close', true, () => {
|
||||
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review ' + diffReviewCloseIcon.classNames, true, () => {
|
||||
this.hide();
|
||||
return Promise.resolve(null);
|
||||
}), { label: false, icon: true });
|
||||
@@ -639,17 +644,17 @@ export class DiffReview extends Disposable {
|
||||
let rowClassName: string = 'diff-review-row';
|
||||
let lineNumbersExtraClassName: string = '';
|
||||
const spacerClassName: string = 'diff-review-spacer';
|
||||
let spacerCodiconName: string | null = null;
|
||||
let spacerIcon: Codicon | null = null;
|
||||
switch (type) {
|
||||
case DiffEntryType.Insert:
|
||||
rowClassName = 'diff-review-row line-insert';
|
||||
lineNumbersExtraClassName = ' char-insert';
|
||||
spacerCodiconName = 'codicon codicon-add';
|
||||
spacerIcon = diffReviewInsertIcon;
|
||||
break;
|
||||
case DiffEntryType.Delete:
|
||||
rowClassName = 'diff-review-row line-delete';
|
||||
lineNumbersExtraClassName = ' char-delete';
|
||||
spacerCodiconName = 'codicon codicon-remove';
|
||||
spacerIcon = diffReviewRemoveIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -713,9 +718,9 @@ export class DiffReview extends Disposable {
|
||||
const spacer = document.createElement('span');
|
||||
spacer.className = spacerClassName;
|
||||
|
||||
if (spacerCodiconName) {
|
||||
if (spacerIcon) {
|
||||
const spacerCodicon = document.createElement('span');
|
||||
spacerCodicon.className = spacerCodiconName;
|
||||
spacerCodicon.className = spacerIcon.classNames;
|
||||
spacerCodicon.innerHTML = '  ';
|
||||
spacer.appendChild(spacerCodicon);
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrow
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IDiffLinesChange {
|
||||
readonly originalStartLineNumber: number;
|
||||
@@ -57,7 +58,7 @@ export class InlineDiffMargin extends Disposable {
|
||||
this._marginDomNode.style.zIndex = '10';
|
||||
|
||||
this._diffActions = document.createElement('div');
|
||||
this._diffActions.className = 'codicon codicon-lightbulb lightbulb-glyph';
|
||||
this._diffActions.className = Codicon.lightBulb.classNames + ' lightbulb-glyph';
|
||||
this._diffActions.style.position = 'absolute';
|
||||
const lineHeight = editor.getOption(EditorOption.lineHeight);
|
||||
const lineFeed = editor.getModel()!.getEOL();
|
||||
|
||||
@@ -1073,7 +1073,7 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorCommentsOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorCommentsOptions;
|
||||
@@ -1259,6 +1259,10 @@ export interface IEditorFindOptions {
|
||||
* Controls if the Find Widget should read or modify the shared find clipboard on macOS
|
||||
*/
|
||||
globalFindClipboard?: boolean;
|
||||
/**
|
||||
* Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found
|
||||
*/
|
||||
loop?: boolean;
|
||||
}
|
||||
|
||||
export type EditorFindOptions = Readonly<Required<IEditorFindOptions>>;
|
||||
@@ -1270,7 +1274,8 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
seedSearchStringFromSelection: true,
|
||||
autoFindInSelection: 'never',
|
||||
globalFindClipboard: false,
|
||||
addExtraSpaceOnTop: true
|
||||
addExtraSpaceOnTop: true,
|
||||
loop: true
|
||||
};
|
||||
super(
|
||||
EditorOption.find, 'find', defaults,
|
||||
@@ -1301,13 +1306,19 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
type: 'boolean',
|
||||
default: defaults.addExtraSpaceOnTop,
|
||||
description: nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.")
|
||||
}
|
||||
},
|
||||
'editor.find.loop': {
|
||||
type: 'boolean',
|
||||
default: defaults.loop,
|
||||
description: nls.localize('find.loop', "Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.")
|
||||
},
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorFindOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorFindOptions;
|
||||
@@ -1317,7 +1328,8 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
? (_input.autoFindInSelection ? 'always' : 'never')
|
||||
: EditorStringEnumOption.stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),
|
||||
globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),
|
||||
addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop)
|
||||
addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),
|
||||
loop: EditorBooleanOption.boolean(input.loop, this.defaultValue.loop),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1532,7 +1544,7 @@ class EditorGoToLocation extends BaseEditorOption<EditorOption.gotoLocation, GoT
|
||||
}
|
||||
|
||||
public validate(_input: any): GoToLocationOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IGotoLocationOptions;
|
||||
@@ -1610,7 +1622,7 @@ class EditorHover extends BaseEditorOption<EditorOption.hover, EditorHoverOption
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorHoverOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorHoverOptions;
|
||||
@@ -2036,7 +2048,7 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, EditorLig
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorLightbulbOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorLightbulbOptions;
|
||||
@@ -2180,7 +2192,7 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, EditorMinimap
|
||||
}
|
||||
|
||||
public validate(_input: any): EditorMinimapOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorMinimapOptions;
|
||||
@@ -2255,7 +2267,7 @@ class EditorPadding extends BaseEditorOption<EditorOption.padding, InternalEdito
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalEditorPaddingOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorPaddingOptions;
|
||||
@@ -2313,7 +2325,7 @@ class EditorParameterHints extends BaseEditorOption<EditorOption.parameterHints,
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalParameterHintOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorParameterHintOptions;
|
||||
@@ -2403,7 +2415,7 @@ class EditorQuickSuggestions extends BaseEditorOption<EditorOption.quickSuggesti
|
||||
if (typeof _input === 'boolean') {
|
||||
return _input;
|
||||
}
|
||||
if (typeof _input === 'object') {
|
||||
if (_input && typeof _input === 'object') {
|
||||
const input = _input as IQuickSuggestionsOptions;
|
||||
const opts = {
|
||||
other: EditorBooleanOption.boolean(input.other, this.defaultValue.other),
|
||||
@@ -2553,7 +2565,7 @@ class EditorRulers extends BaseEditorOption<EditorOption.rulers, IRulerOption[]>
|
||||
column: EditorIntOption.clampedInt(_element, 0, 0, 10000),
|
||||
color: null
|
||||
});
|
||||
} else if (typeof _element === 'object') {
|
||||
} else if (_element && typeof _element === 'object') {
|
||||
const element = _element as IRulerOption;
|
||||
rulers.push({
|
||||
column: EditorIntOption.clampedInt(element.column, 0, 0, 10000),
|
||||
@@ -2687,7 +2699,7 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalEditorScrollbarOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as IEditorScrollbarOptions;
|
||||
@@ -3108,7 +3120,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, InternalSugge
|
||||
}
|
||||
|
||||
public validate(_input: any): InternalSuggestOptions {
|
||||
if (typeof _input !== 'object') {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
const input = _input as ISuggestOptions;
|
||||
|
||||
@@ -10,6 +10,7 @@ export namespace EditorContextKeys {
|
||||
export const editorSimpleInput = new RawContextKey<boolean>('editorSimpleInput', false);
|
||||
/**
|
||||
* A context key that is set when the editor's text has focus (cursor is blinking).
|
||||
* Is false when focus is in simple editor widgets (repl input, scm commit input).
|
||||
*/
|
||||
export const editorTextFocus = new RawContextKey<boolean>('editorTextFocus', false);
|
||||
/**
|
||||
|
||||
@@ -56,77 +56,80 @@ export function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegEx
|
||||
return result;
|
||||
}
|
||||
|
||||
function getWordAtPosFast(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
// find whitespace enclosed text around column and match from there
|
||||
const _defaultConfig = {
|
||||
maxLen: 1000,
|
||||
windowSize: 15,
|
||||
timeBudget: 150
|
||||
};
|
||||
|
||||
let pos = column - 1 - textOffset;
|
||||
let start = text.lastIndexOf(' ', pos - 1) + 1;
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config = _defaultConfig): IWordAtPosition | null {
|
||||
|
||||
wordDefinition.lastIndex = start;
|
||||
if (text.length > config.maxLen) {
|
||||
// don't throw strings that long at the regexp
|
||||
// but use a sub-string in which a word must occur
|
||||
let start = column - config.maxLen / 2;
|
||||
if (start < 0) {
|
||||
textOffset += column;
|
||||
start = 0;
|
||||
} else {
|
||||
textOffset += start;
|
||||
}
|
||||
text = text.substring(start, column + config.maxLen / 2);
|
||||
return getWordAtText(column, wordDefinition, text, textOffset, config);
|
||||
}
|
||||
|
||||
const t1 = Date.now();
|
||||
const pos = column - 1 - textOffset;
|
||||
|
||||
let prevRegexIndex = -1;
|
||||
let match: RegExpMatchArray | null = null;
|
||||
|
||||
for (let i = 1; ; i++) {
|
||||
// check time budget
|
||||
if (Date.now() - t1 >= config.timeBudget) {
|
||||
// break;
|
||||
}
|
||||
|
||||
// reset the index at which the regexp should start matching, also know where it
|
||||
// should stop so that subsequent search don't repeat previous searches
|
||||
const regexIndex = pos - config.windowSize * i;
|
||||
wordDefinition.lastIndex = Math.max(0, regexIndex);
|
||||
match = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);
|
||||
|
||||
// stop: found something
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
|
||||
// stop: searched at start
|
||||
if (regexIndex <= 0) {
|
||||
break;
|
||||
}
|
||||
prevRegexIndex = regexIndex;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
let result = {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + match.index!,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
wordDefinition.lastIndex = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpMatchArray | null {
|
||||
let match: RegExpMatchArray | null;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
const matchIndex = match.index || 0;
|
||||
if (matchIndex <= pos && wordDefinition.lastIndex >= pos) {
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + matchIndex,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function getWordAtPosSlow(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
// matches all words starting at the beginning
|
||||
// of the input until it finds a match that encloses
|
||||
// the desired column. slow but correct
|
||||
|
||||
let pos = column - 1 - textOffset;
|
||||
wordDefinition.lastIndex = 0;
|
||||
|
||||
let match: RegExpMatchArray | null;
|
||||
while (match = wordDefinition.exec(text)) {
|
||||
const matchIndex = match.index || 0;
|
||||
if (matchIndex > pos) {
|
||||
// |nW -> matched only after the pos
|
||||
return match;
|
||||
} else if (stopPos > 0 && matchIndex > stopPos) {
|
||||
return null;
|
||||
|
||||
} else if (wordDefinition.lastIndex >= pos) {
|
||||
// W|W -> match encloses pos
|
||||
return {
|
||||
word: match[0],
|
||||
startColumn: textOffset + 1 + matchIndex,
|
||||
endColumn: textOffset + 1 + wordDefinition.lastIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number): IWordAtPosition | null {
|
||||
|
||||
// if `words` can contain whitespace character we have to use the slow variant
|
||||
// otherwise we use the fast variant of finding a word
|
||||
wordDefinition.lastIndex = 0;
|
||||
let match = wordDefinition.exec(text);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
// todo@joh the `match` could already be the (first) word
|
||||
const ret = match[0].indexOf(' ') >= 0
|
||||
// did match a word which contains a space character -> use slow word find
|
||||
? getWordAtPosSlow(column, wordDefinition, text, textOffset)
|
||||
// sane word definition -> use fast word find
|
||||
: getWordAtPosFast(column, wordDefinition, text, textOffset);
|
||||
|
||||
// both (getWordAtPosFast and getWordAtPosSlow) leave the wordDefinition-RegExp
|
||||
// in an undefined state and to not confuse other users of the wordDefinition
|
||||
// we reset the lastIndex
|
||||
wordDefinition.lastIndex = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureR
|
||||
import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { iconRegistry, Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
/**
|
||||
* Open ended enum at runtime
|
||||
@@ -359,7 +360,13 @@ export const completionKindToCssClass = (function () {
|
||||
data[CompletionItemKind.Issue] = 'issues';
|
||||
|
||||
return function (kind: CompletionItemKind) {
|
||||
return data[kind] || 'property';
|
||||
const name = data[kind];
|
||||
let codicon = name && iconRegistry.get(name);
|
||||
if (!codicon) {
|
||||
console.info('No codicon found for CompletionItemKind ' + kind);
|
||||
codicon = Codicon.symbolProperty;
|
||||
}
|
||||
return codicon.classNames;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -697,6 +704,12 @@ export interface SignatureInformation {
|
||||
* The parameters of this signature.
|
||||
*/
|
||||
parameters: ParameterInformation[];
|
||||
/**
|
||||
* Index of the active parameter.
|
||||
*
|
||||
* If provided, this is used in place of `SignatureHelp.activeSignature`.
|
||||
*/
|
||||
activeParameter?: number;
|
||||
}
|
||||
/**
|
||||
* Signature help represents the signature of something
|
||||
@@ -1037,7 +1050,13 @@ export namespace SymbolKinds {
|
||||
* @internal
|
||||
*/
|
||||
export function toCssClassName(kind: SymbolKind, inline?: boolean): string {
|
||||
return `codicon ${inline ? 'inline' : 'block'} codicon-symbol-${byKind.get(kind) || 'property'}`;
|
||||
const symbolName = byKind.get(kind);
|
||||
let codicon = symbolName && iconRegistry.get('symbol-' + symbolName);
|
||||
if (!codicon) {
|
||||
console.info('No codicon found for SymbolKind ' + kind);
|
||||
codicon = Codicon.symbolProperty;
|
||||
}
|
||||
return `${inline ? 'inline' : 'block'} ${codicon.classNames}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1393,7 +1412,10 @@ export interface RenameProvider {
|
||||
export interface AuthenticationSession {
|
||||
id: string;
|
||||
getAccessToken(): Thenable<string>;
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -114,7 +114,7 @@ class EditorScrollable extends Disposable {
|
||||
scrollWidth: dimensions.scrollWidth,
|
||||
height: dimensions.height,
|
||||
scrollHeight: dimensions.scrollHeight
|
||||
});
|
||||
}, true);
|
||||
|
||||
const contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);
|
||||
const contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);
|
||||
|
||||
@@ -35,6 +35,12 @@ export interface CodeActionSet extends IDisposable {
|
||||
class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
||||
|
||||
private static codeActionsComparator(a: modes.CodeAction, b: modes.CodeAction): number {
|
||||
if (a.isPreferred && !b.isPreferred) {
|
||||
return -1;
|
||||
} else if (!a.isPreferred && b.isPreferred) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(a.diagnostics)) {
|
||||
if (isNonEmptyArray(b.diagnostics)) {
|
||||
return a.diagnostics[0].message.localeCompare(b.diagnostics[0].message);
|
||||
|
||||
@@ -19,6 +19,7 @@ import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/
|
||||
import { editorLightBulbForeground, editorLightBulbAutoFixForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Gesture } from 'vs/base/browser/touch';
|
||||
import type { CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
namespace LightBulbState {
|
||||
|
||||
@@ -63,7 +64,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
) {
|
||||
super();
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'codicon codicon-lightbulb';
|
||||
this._domNode.className = Codicon.lightBulb.classNames;
|
||||
|
||||
this._editor.addContentWidget(this);
|
||||
|
||||
@@ -121,8 +122,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
}));
|
||||
|
||||
this._updateLightBulbTitle();
|
||||
this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this));
|
||||
this._updateLightBulbTitleAndIcon();
|
||||
this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitleAndIcon, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -184,7 +185,6 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
position: { lineNumber: effectiveLineNumber, column: 1 },
|
||||
preference: LightBulbWidget._posPref
|
||||
});
|
||||
dom.toggleClass(this._domNode, 'codicon-lightbulb-autofix', actions.hasAutoFix);
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
@@ -197,11 +197,15 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
|
||||
private set state(value) {
|
||||
this._state = value;
|
||||
this._updateLightBulbTitle();
|
||||
this._updateLightBulbTitleAndIcon();
|
||||
}
|
||||
|
||||
private _updateLightBulbTitle(): void {
|
||||
private _updateLightBulbTitleAndIcon(): void {
|
||||
if (this.state.type === LightBulbState.Type.Showing && this.state.actions.hasAutoFix) {
|
||||
// update icon
|
||||
dom.removeClasses(this._domNode, Codicon.lightBulb.classNames);
|
||||
dom.addClasses(this._domNode, Codicon.lightbulbAutofix.classNames);
|
||||
|
||||
const preferredKb = this._keybindingService.lookupKeybinding(this._preferredFixActionId);
|
||||
if (preferredKb) {
|
||||
this.title = nls.localize('prefferedQuickFixWithKb', "Show Fixes. Preferred Fix Available ({0})", preferredKb.getLabel());
|
||||
@@ -209,6 +213,10 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// update icon
|
||||
dom.removeClasses(this._domNode, Codicon.lightbulbAutofix.classNames);
|
||||
dom.addClasses(this._domNode, Codicon.lightBulb.classNames);
|
||||
|
||||
const kb = this._keybindingService.lookupKeybinding(this._quickFixActionId);
|
||||
if (kb) {
|
||||
this.title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel());
|
||||
@@ -228,7 +236,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
const editorLightBulbForegroundColor = theme.getColor(editorLightBulbForeground);
|
||||
if (editorLightBulbForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .contentWidgets .codicon-lightbulb {
|
||||
.monaco-editor .contentWidgets ${Codicon.lightBulb.cssSelector} {
|
||||
color: ${editorLightBulbForegroundColor};
|
||||
}`);
|
||||
}
|
||||
@@ -237,7 +245,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
const editorLightBulbAutoFixForegroundColor = theme.getColor(editorLightBulbAutoFixForeground);
|
||||
if (editorLightBulbAutoFixForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .contentWidgets .codicon-lightbulb-autofix {
|
||||
.monaco-editor .contentWidgets ${Codicon.lightbulbAutofix.cssSelector} {
|
||||
color: ${editorLightBulbAutoFixForegroundColor};
|
||||
}`);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export class CodeLensContribution implements IEditorContribution {
|
||||
}));
|
||||
this._onModelChange();
|
||||
|
||||
this._styleClassName = hash(this._editor.getId()).toString(16);
|
||||
this._styleClassName = '_' + hash(this._editor.getId()).toString(16);
|
||||
this._styleElement = dom.createStyleSheet(
|
||||
dom.isInShadowDOM(this._editor.getContainerDomNode())
|
||||
? this._editor.getContainerDomNode()
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { binarySearch, coalesceInPlace, equals } from 'vs/base/common/arrays';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { first, forEach, size } from 'vs/base/common/collections';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { commonPrefixLength } from 'vs/base/common/strings';
|
||||
@@ -14,18 +13,21 @@ import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { DocumentSymbol, DocumentSymbolProvider, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { MovingAverage } from 'vs/base/common/numbers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export abstract class TreeElement {
|
||||
|
||||
abstract id: string;
|
||||
abstract children: { [id: string]: TreeElement };
|
||||
abstract children: Map<string, TreeElement>;
|
||||
abstract parent: TreeElement | undefined;
|
||||
|
||||
abstract adopt(newParent: TreeElement): TreeElement;
|
||||
|
||||
remove(): void {
|
||||
if (this.parent) {
|
||||
delete this.parent.children[this.id];
|
||||
this.parent.children.delete(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +39,13 @@ export abstract class TreeElement {
|
||||
candidateId = `${container.id}/${candidate}`;
|
||||
} else {
|
||||
candidateId = `${container.id}/${candidate.name}`;
|
||||
if (container.children[candidateId] !== undefined) {
|
||||
if (container.children.get(candidateId) !== undefined) {
|
||||
candidateId = `${container.id}/${candidate.name}_${candidate.range.startLineNumber}_${candidate.range.startColumn}`;
|
||||
}
|
||||
}
|
||||
|
||||
let id = candidateId;
|
||||
for (let i = 0; container.children[id] !== undefined; i++) {
|
||||
for (let i = 0; container.children.get(id) !== undefined; i++) {
|
||||
id = `${candidateId}_${i}`;
|
||||
}
|
||||
|
||||
@@ -61,8 +63,8 @@ export abstract class TreeElement {
|
||||
if (len < element.id.length) {
|
||||
return undefined;
|
||||
}
|
||||
for (const key in element.children) {
|
||||
let candidate = TreeElement.getElementById(id, element.children[key]);
|
||||
for (const [, child] of element.children) {
|
||||
let candidate = TreeElement.getElementById(id, child);
|
||||
if (candidate) {
|
||||
return candidate;
|
||||
}
|
||||
@@ -72,17 +74,14 @@ export abstract class TreeElement {
|
||||
|
||||
static size(element: TreeElement): number {
|
||||
let res = 1;
|
||||
for (const key in element.children) {
|
||||
res += TreeElement.size(element.children[key]);
|
||||
for (const [, child] of element.children) {
|
||||
res += TreeElement.size(child);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static empty(element: TreeElement): boolean {
|
||||
for (const _key in element.children) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return element.children.size === 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ export interface IOutlineMarker {
|
||||
|
||||
export class OutlineElement extends TreeElement {
|
||||
|
||||
children: { [id: string]: OutlineElement; } = Object.create(null);
|
||||
children = new Map<string, OutlineElement>();
|
||||
marker: { count: number, topSev: MarkerSeverity } | undefined;
|
||||
|
||||
constructor(
|
||||
@@ -109,27 +108,31 @@ export class OutlineElement extends TreeElement {
|
||||
|
||||
adopt(parent: TreeElement): OutlineElement {
|
||||
let res = new OutlineElement(this.id, parent, this.symbol);
|
||||
forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res));
|
||||
for (const [key, value] of this.children) {
|
||||
res.children.set(key, value.adopt(res));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineGroup extends TreeElement {
|
||||
|
||||
children: { [id: string]: OutlineElement; } = Object.create(null);
|
||||
children = new Map<string, OutlineElement>();
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
public parent: TreeElement | undefined,
|
||||
readonly provider: DocumentSymbolProvider,
|
||||
readonly providerIndex: number,
|
||||
readonly label: string,
|
||||
readonly order: number,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
adopt(parent: TreeElement): OutlineGroup {
|
||||
let res = new OutlineGroup(this.id, parent, this.provider, this.providerIndex);
|
||||
forEach(this.children, entry => res.children[entry.key] = entry.value.adopt(res));
|
||||
let res = new OutlineGroup(this.id, parent, this.label, this.order);
|
||||
for (const [key, value] of this.children) {
|
||||
res.children.set(key, value.adopt(res));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -137,9 +140,8 @@ export class OutlineGroup extends TreeElement {
|
||||
return position ? this._getItemEnclosingPosition(position, this.children) : undefined;
|
||||
}
|
||||
|
||||
private _getItemEnclosingPosition(position: IPosition, children: { [id: string]: OutlineElement }): OutlineElement | undefined {
|
||||
for (let key in children) {
|
||||
let item = children[key];
|
||||
private _getItemEnclosingPosition(position: IPosition, children: Map<string, OutlineElement>): OutlineElement | undefined {
|
||||
for (const [, item] of children) {
|
||||
if (!item.symbol.range || !Range.containsPosition(item.symbol.range, position)) {
|
||||
continue;
|
||||
}
|
||||
@@ -149,8 +151,8 @@ export class OutlineGroup extends TreeElement {
|
||||
}
|
||||
|
||||
updateMarker(marker: IOutlineMarker[]): void {
|
||||
for (const key in this.children) {
|
||||
this._updateMarker(marker, this.children[key]);
|
||||
for (const [, child] of this.children) {
|
||||
this._updateMarker(marker, child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,8 +189,8 @@ export class OutlineGroup extends TreeElement {
|
||||
// this outline element. This might remove markers from this element and
|
||||
// therefore we remember that we have had markers. That allows us to render
|
||||
// the dot, saying 'this element has children with markers'
|
||||
for (const key in item.children) {
|
||||
this._updateMarker(myMarkers, item.children[key]);
|
||||
for (const [, child] of item.children) {
|
||||
this._updateMarker(myMarkers, child);
|
||||
}
|
||||
|
||||
if (myTopSev) {
|
||||
@@ -202,21 +204,7 @@ export class OutlineGroup extends TreeElement {
|
||||
}
|
||||
}
|
||||
|
||||
class MovingAverage {
|
||||
|
||||
private _n = 1;
|
||||
private _val = 0;
|
||||
|
||||
update(value: number): this {
|
||||
this._val = this._val + (value - this._val) / this._n;
|
||||
this._n += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this._val;
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineModel extends TreeElement {
|
||||
|
||||
@@ -315,14 +303,14 @@ export class OutlineModel extends TreeElement {
|
||||
private static _create(textModel: ITextModel, token: CancellationToken): Promise<OutlineModel> {
|
||||
|
||||
const cts = new CancellationTokenSource(token);
|
||||
const result = new OutlineModel(textModel);
|
||||
const result = new OutlineModel(textModel.uri);
|
||||
const provider = DocumentSymbolProviderRegistry.ordered(textModel);
|
||||
const promises = provider.map((provider, index) => {
|
||||
|
||||
let id = TreeElement.findId(`provider_${index}`, result);
|
||||
let group = new OutlineGroup(id, result, provider, index);
|
||||
let group = new OutlineGroup(id, result, provider.displayName ?? 'Unknown Outline Provider', index);
|
||||
|
||||
return Promise.resolve(provider.provideDocumentSymbols(result.textModel, cts.token)).then(result => {
|
||||
return Promise.resolve(provider.provideDocumentSymbols(textModel, cts.token)).then(result => {
|
||||
for (const info of result || []) {
|
||||
OutlineModel._makeOutlineElement(info, group);
|
||||
}
|
||||
@@ -332,7 +320,7 @@ export class OutlineModel extends TreeElement {
|
||||
return group;
|
||||
}).then(group => {
|
||||
if (!TreeElement.empty(group)) {
|
||||
result._groups[id] = group;
|
||||
result._groups.set(id, group);
|
||||
} else {
|
||||
group.remove();
|
||||
}
|
||||
@@ -365,7 +353,7 @@ export class OutlineModel extends TreeElement {
|
||||
OutlineModel._makeOutlineElement(childInfo, res);
|
||||
}
|
||||
}
|
||||
container.children[res.id] = res;
|
||||
container.children.set(res.id, res);
|
||||
}
|
||||
|
||||
static get(element: TreeElement | undefined): OutlineModel | undefined {
|
||||
@@ -381,10 +369,10 @@ export class OutlineModel extends TreeElement {
|
||||
readonly id = 'root';
|
||||
readonly parent = undefined;
|
||||
|
||||
protected _groups: { [id: string]: OutlineGroup; } = Object.create(null);
|
||||
children: { [id: string]: OutlineGroup | OutlineElement; } = Object.create(null);
|
||||
protected _groups = new Map<string, OutlineGroup>();
|
||||
children = new Map<string, OutlineGroup | OutlineElement>();
|
||||
|
||||
protected constructor(readonly textModel: ITextModel) {
|
||||
protected constructor(readonly uri: URI) {
|
||||
super();
|
||||
|
||||
this.id = 'root';
|
||||
@@ -392,17 +380,18 @@ export class OutlineModel extends TreeElement {
|
||||
}
|
||||
|
||||
adopt(): OutlineModel {
|
||||
let res = new OutlineModel(this.textModel);
|
||||
forEach(this._groups, entry => res._groups[entry.key] = entry.value.adopt(res));
|
||||
let res = new OutlineModel(this.uri);
|
||||
for (const [key, value] of this._groups) {
|
||||
res._groups.set(key, value.adopt(res));
|
||||
}
|
||||
return res._compact();
|
||||
}
|
||||
|
||||
private _compact(): this {
|
||||
let count = 0;
|
||||
for (const key in this._groups) {
|
||||
let group = this._groups[key];
|
||||
if (first(group.children) === undefined) { // empty
|
||||
delete this._groups[key];
|
||||
for (const [key, group] of this._groups) {
|
||||
if (group.children.size === 0) { // empty
|
||||
this._groups.delete(key);
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
@@ -412,21 +401,20 @@ export class OutlineModel extends TreeElement {
|
||||
this.children = this._groups;
|
||||
} else {
|
||||
// adopt all elements of the first group
|
||||
let group = first(this._groups);
|
||||
for (let key in group!.children) {
|
||||
let child = group!.children[key];
|
||||
let group = Iterable.first(this._groups.values())!;
|
||||
for (let [, child] of group.children) {
|
||||
child.parent = this;
|
||||
this.children[child.id] = child;
|
||||
this.children.set(child.id, child);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
merge(other: OutlineModel): boolean {
|
||||
if (this.textModel.uri.toString() !== other.textModel.uri.toString()) {
|
||||
if (this.uri.toString() !== other.uri.toString()) {
|
||||
return false;
|
||||
}
|
||||
if (size(this._groups) !== size(other._groups)) {
|
||||
if (this._groups.size !== other._groups.size) {
|
||||
return false;
|
||||
}
|
||||
this._groups = other._groups;
|
||||
@@ -448,8 +436,7 @@ export class OutlineModel extends TreeElement {
|
||||
}
|
||||
|
||||
let result: OutlineElement | undefined = undefined;
|
||||
for (const key in this._groups) {
|
||||
const group = this._groups[key];
|
||||
for (const [, group] of this._groups) {
|
||||
result = group.getItemEnclosingPosition(position);
|
||||
if (result && (!preferredGroup || preferredGroup === group)) {
|
||||
break;
|
||||
@@ -467,8 +454,8 @@ export class OutlineModel extends TreeElement {
|
||||
// outline element starts for quicker look up
|
||||
marker.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
for (const key in this._groups) {
|
||||
this._groups[key].updateMarker(marker.slice(0));
|
||||
for (const [, group] of this._groups) {
|
||||
group.updateMarker(marker.slice(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import * as dom from 'vs/base/browser/dom';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IDataSource, ITreeNode, ITreeRenderer, ITreeSorter, ITreeFilter } from 'vs/base/browser/ui/tree/tree';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import 'vs/css!./media/outlineTree';
|
||||
import 'vs/css!./media/symbol-icons';
|
||||
@@ -24,6 +23,9 @@ import { registerColor, listErrorForeground, listWarningForeground, foreground }
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export type OutlineItem = OutlineGroup | OutlineElement;
|
||||
|
||||
@@ -31,13 +33,29 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP
|
||||
|
||||
getKeyboardNavigationLabel(element: OutlineItem): { toString(): string; } {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return element.provider.displayName || element.id;
|
||||
return element.label;
|
||||
} else {
|
||||
return element.symbol.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineAccessibilityProvider implements IListAccessibilityProvider<OutlineItem> {
|
||||
|
||||
constructor(private readonly ariaLabel: string) { }
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return this.ariaLabel;
|
||||
}
|
||||
|
||||
getAriaLabel(element: OutlineItem): string | null {
|
||||
if (element instanceof OutlineGroup) {
|
||||
return element.label;
|
||||
} else {
|
||||
return element.symbol.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OutlineIdentityProvider implements IIdentityProvider<OutlineItem> {
|
||||
getId(element: OutlineItem): { toString(): string; } {
|
||||
@@ -91,7 +109,7 @@ export class OutlineGroupRenderer implements ITreeRenderer<OutlineGroup, FuzzySc
|
||||
|
||||
renderElement(node: ITreeNode<OutlineGroup, FuzzyScore>, index: number, template: OutlineGroupTemplate): void {
|
||||
template.label.set(
|
||||
node.element.provider.displayName || localize('provider', "Outline Provider"),
|
||||
node.element.label,
|
||||
createMatches(node.filterData)
|
||||
);
|
||||
}
|
||||
@@ -290,7 +308,7 @@ export class OutlineFilter implements ITreeFilter<OutlineItem> {
|
||||
let uri: URI | undefined;
|
||||
|
||||
if (outline) {
|
||||
uri = outline.textModel.uri;
|
||||
uri = outline.uri;
|
||||
}
|
||||
|
||||
if (!(element instanceof OutlineElement)) {
|
||||
@@ -313,7 +331,7 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
|
||||
|
||||
compare(a: OutlineItem, b: OutlineItem): number {
|
||||
if (a instanceof OutlineGroup && b instanceof OutlineGroup) {
|
||||
return a.providerIndex - b.providerIndex;
|
||||
return a.order - b.order;
|
||||
|
||||
} else if (a instanceof OutlineElement && b instanceof OutlineElement) {
|
||||
if (this.type === OutlineSortOrder.ByKind) {
|
||||
@@ -330,11 +348,11 @@ export class OutlineItemComparator implements ITreeSorter<OutlineItem> {
|
||||
|
||||
export class OutlineDataSource implements IDataSource<OutlineModel, OutlineItem> {
|
||||
|
||||
getChildren(element: undefined | OutlineModel | OutlineGroup | OutlineElement): OutlineItem[] {
|
||||
getChildren(element: undefined | OutlineModel | OutlineGroup | OutlineElement) {
|
||||
if (!element) {
|
||||
return [];
|
||||
return Iterable.empty();
|
||||
}
|
||||
return values(element.children);
|
||||
return element.children.values();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,168 +558,168 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
|
||||
const symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND);
|
||||
if (symbolIconArrayColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-array { color: ${symbolIconArrayColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolArray.cssSelector} { color: ${symbolIconArrayColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND);
|
||||
if (symbolIconBooleanColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-boolean { color: ${symbolIconBooleanColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolBoolean.cssSelector} { color: ${symbolIconBooleanColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND);
|
||||
if (symbolIconClassColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-class { color: ${symbolIconClassColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolClass.cssSelector} { color: ${symbolIconClassColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND);
|
||||
if (symbolIconMethodColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-method { color: ${symbolIconMethodColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolMethod.cssSelector} { color: ${symbolIconMethodColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconColorColor = theme.getColor(SYMBOL_ICON_COLOR_FOREGROUND);
|
||||
if (symbolIconColorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-color { color: ${symbolIconColorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolColor.cssSelector} { color: ${symbolIconColorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND);
|
||||
if (symbolIconConstantColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-constant { color: ${symbolIconConstantColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolConstant.cssSelector} { color: ${symbolIconConstantColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND);
|
||||
if (symbolIconConstructorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-constructor { color: ${symbolIconConstructorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolConstructor.cssSelector} { color: ${symbolIconConstructorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND);
|
||||
if (symbolIconEnumeratorColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-symbol-value,.monaco-workbench .codicon-symbol-enum { color: ${symbolIconEnumeratorColor}; }`);
|
||||
.monaco-workbench ${Codicon.symbolValue.cssSelector},.monaco-workbench ${Codicon.symbolEnum.cssSelector} { color: ${symbolIconEnumeratorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND);
|
||||
if (symbolIconEnumeratorMemberColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-enum-member { color: ${symbolIconEnumeratorMemberColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolEnumMember.cssSelector} { color: ${symbolIconEnumeratorMemberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND);
|
||||
if (symbolIconEventColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-event { color: ${symbolIconEventColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolEvent.cssSelector} { color: ${symbolIconEventColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND);
|
||||
if (symbolIconFieldColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-field { color: ${symbolIconFieldColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolField.cssSelector} { color: ${symbolIconFieldColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND);
|
||||
if (symbolIconFileColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-file { color: ${symbolIconFileColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFile.cssSelector} { color: ${symbolIconFileColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFolderColor = theme.getColor(SYMBOL_ICON_FOLDER_FOREGROUND);
|
||||
if (symbolIconFolderColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-folder { color: ${symbolIconFolderColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFolder.cssSelector} { color: ${symbolIconFolderColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND);
|
||||
if (symbolIconFunctionColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-function { color: ${symbolIconFunctionColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolFunction.cssSelector} { color: ${symbolIconFunctionColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND);
|
||||
if (symbolIconInterfaceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-interface { color: ${symbolIconInterfaceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolInterface.cssSelector} { color: ${symbolIconInterfaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND);
|
||||
if (symbolIconKeyColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-key { color: ${symbolIconKeyColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolKey.cssSelector} { color: ${symbolIconKeyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconKeywordColor = theme.getColor(SYMBOL_ICON_KEYWORD_FOREGROUND);
|
||||
if (symbolIconKeywordColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-keyword { color: ${symbolIconKeywordColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolKeyword.cssSelector} { color: ${symbolIconKeywordColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND);
|
||||
if (symbolIconModuleColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-module { color: ${symbolIconModuleColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolModule.cssSelector} { color: ${symbolIconModuleColor}; }`);
|
||||
}
|
||||
|
||||
const outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND);
|
||||
if (outlineNamespaceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-namespace { color: ${outlineNamespaceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNamespace.cssSelector} { color: ${outlineNamespaceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND);
|
||||
if (symbolIconNullColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-null { color: ${symbolIconNullColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNull.cssSelector} { color: ${symbolIconNullColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND);
|
||||
if (symbolIconNumberColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-number { color: ${symbolIconNumberColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolNumber.cssSelector} { color: ${symbolIconNumberColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND);
|
||||
if (symbolIconObjectColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-object { color: ${symbolIconObjectColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolObject.cssSelector} { color: ${symbolIconObjectColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND);
|
||||
if (symbolIconOperatorColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-operator { color: ${symbolIconOperatorColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolOperator.cssSelector} { color: ${symbolIconOperatorColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND);
|
||||
if (symbolIconPackageColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-package { color: ${symbolIconPackageColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolPackage.cssSelector} { color: ${symbolIconPackageColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND);
|
||||
if (symbolIconPropertyColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-property { color: ${symbolIconPropertyColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolProperty.cssSelector} { color: ${symbolIconPropertyColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconReferenceColor = theme.getColor(SYMBOL_ICON_REFERENCE_FOREGROUND);
|
||||
if (symbolIconReferenceColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-reference { color: ${symbolIconReferenceColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolReference.cssSelector} { color: ${symbolIconReferenceColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconSnippetColor = theme.getColor(SYMBOL_ICON_SNIPPET_FOREGROUND);
|
||||
if (symbolIconSnippetColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-snippet { color: ${symbolIconSnippetColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolSnippet.cssSelector} { color: ${symbolIconSnippetColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND);
|
||||
if (symbolIconStringColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-string { color: ${symbolIconStringColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolString.cssSelector} { color: ${symbolIconStringColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND);
|
||||
if (symbolIconStructColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-struct { color: ${symbolIconStructColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolStruct.cssSelector} { color: ${symbolIconStructColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTextColor = theme.getColor(SYMBOL_ICON_TEXT_FOREGROUND);
|
||||
if (symbolIconTextColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-text { color: ${symbolIconTextColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolText.cssSelector} { color: ${symbolIconTextColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND);
|
||||
if (symbolIconTypeParameterColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-type-parameter { color: ${symbolIconTypeParameterColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolTypeParameter.cssSelector} { color: ${symbolIconTypeParameterColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconUnitColor = theme.getColor(SYMBOL_ICON_UNIT_FOREGROUND);
|
||||
if (symbolIconUnitColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-unit { color: ${symbolIconUnitColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolUnit.cssSelector} { color: ${symbolIconUnitColor}; }`);
|
||||
}
|
||||
|
||||
const symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND);
|
||||
if (symbolIconVariableColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-symbol-variable { color: ${symbolIconVariableColor}; }`);
|
||||
collector.addRule(`.monaco-workbench ${Codicon.symbolVariable.cssSelector} { color: ${symbolIconVariableColor}; }`);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -93,9 +93,9 @@ suite('OutlineModel', function () {
|
||||
let e2 = new OutlineElement('foo3', null!, fakeSymbolInformation(new Range(6, 1, 10, 10)));
|
||||
|
||||
let group = new OutlineGroup('group', null!, null!, 1);
|
||||
group.children[e0.id] = e0;
|
||||
group.children[e1.id] = e1;
|
||||
group.children[e2.id] = e2;
|
||||
group.children.set(e0.id, e0);
|
||||
group.children.set(e1.id, e1);
|
||||
group.children.set(e2.id, e2);
|
||||
|
||||
const data = [fakeMarker(new Range(6, 1, 6, 7)), fakeMarker(new Range(1, 1, 1, 4)), fakeMarker(new Range(10, 2, 14, 1))];
|
||||
data.sort(Range.compareRangesUsingStarts); // model does this
|
||||
@@ -119,9 +119,9 @@ suite('OutlineModel', function () {
|
||||
let c2 = new OutlineElement('A/C', null!, fakeSymbolInformation(new Range(6, 4, 9, 4)));
|
||||
|
||||
let group = new OutlineGroup('group', null!, null!, 1);
|
||||
group.children[p.id] = p;
|
||||
p.children[c1.id] = c1;
|
||||
p.children[c2.id] = c2;
|
||||
group.children.set(p.id, p);
|
||||
p.children.set(c1.id, c1);
|
||||
p.children.set(c2.id, c2);
|
||||
|
||||
let data = [
|
||||
fakeMarker(new Range(2, 4, 5, 4))
|
||||
@@ -162,13 +162,13 @@ suite('OutlineModel', function () {
|
||||
this._groups = this.children as any;
|
||||
}
|
||||
};
|
||||
model.children['g1'] = new OutlineGroup('g1', model, null!, 1);
|
||||
model.children['g1'].children['c1'] = new OutlineElement('c1', model.children['g1'], fakeSymbolInformation(new Range(1, 1, 11, 1)));
|
||||
model.children.set('g1', new OutlineGroup('g1', model, null!, 1));
|
||||
model.children.get('g1')!.children.set('c1', new OutlineElement('c1', model.children.get('g1')!, fakeSymbolInformation(new Range(1, 1, 11, 1))));
|
||||
|
||||
model.children['g2'] = new OutlineGroup('g2', model, null!, 1);
|
||||
model.children['g2'].children['c2'] = new OutlineElement('c2', model.children['g2'], fakeSymbolInformation(new Range(1, 1, 7, 1)));
|
||||
model.children['g2'].children['c2'].children['c2.1'] = new OutlineElement('c2.1', model.children['g2'].children['c2'], fakeSymbolInformation(new Range(1, 3, 2, 19)));
|
||||
model.children['g2'].children['c2'].children['c2.2'] = new OutlineElement('c2.2', model.children['g2'].children['c2'], fakeSymbolInformation(new Range(4, 1, 6, 10)));
|
||||
model.children.set('g2', new OutlineGroup('g2', model, null!, 1));
|
||||
model.children.get('g2')!.children.set('c2', new OutlineElement('c2', model.children.get('g2')!, fakeSymbolInformation(new Range(1, 1, 7, 1))));
|
||||
model.children.get('g2')!.children.get('c2')!.children.set('c2.1', new OutlineElement('c2.1', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(1, 3, 2, 19))));
|
||||
model.children.get('g2')!.children.get('c2')!.children.set('c2.2', new OutlineElement('c2.2', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(4, 1, 6, 10))));
|
||||
|
||||
model.readyForTesting();
|
||||
|
||||
@@ -179,9 +179,9 @@ suite('OutlineModel', function () {
|
||||
|
||||
model.updateMarker(data);
|
||||
|
||||
assert.equal(model.children['g1']!.children['c1'].marker!.count, 2);
|
||||
assert.equal(model.children['g2']!.children['c2'].children['c2.1'].marker!.count, 1);
|
||||
assert.equal(model.children['g2']!.children['c2'].children['c2.2'].marker!.count, 1);
|
||||
assert.equal(model.children.get('g1')!.children.get('c1')!.marker!.count, 2);
|
||||
assert.equal(model.children.get('g2')!.children.get('c2')!.children.get('c2.1')!.marker!.count, 1);
|
||||
assert.equal(model.children.get('g2')!.children.get('c2')!.children.get('c2.2')!.marker!.count, 1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
const SEARCH_STRING_MAX_LENGTH = 524288;
|
||||
|
||||
@@ -66,6 +67,7 @@ export interface IFindStartOptions {
|
||||
shouldFocus: FindStartFocusAction;
|
||||
shouldAnimate: boolean;
|
||||
updateSearchScope: boolean;
|
||||
loop: boolean;
|
||||
}
|
||||
|
||||
export class CommonFindController extends Disposable implements IEditorContribution {
|
||||
@@ -125,7 +127,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: this._editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}));
|
||||
@@ -296,6 +299,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
}
|
||||
|
||||
stateChanges.loop = opts.loop;
|
||||
|
||||
this._state.change(stateChanges, false);
|
||||
|
||||
if (!this._model) {
|
||||
@@ -383,6 +388,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IStorageService _storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService private readonly _storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
@optional(IClipboardService) clipboardService: IClipboardService,
|
||||
) {
|
||||
super(editor, _contextKeyService, _storageService, clipboardService);
|
||||
@@ -437,7 +443,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
}
|
||||
|
||||
private _createFindWidget() {
|
||||
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService));
|
||||
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService, this._storageKeysSyncRegistryService));
|
||||
this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));
|
||||
}
|
||||
}
|
||||
@@ -473,7 +479,8 @@ export class StartFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -507,7 +514,8 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
|
||||
controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
@@ -524,7 +532,8 @@ export abstract class MatchFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: true,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -636,7 +645,8 @@ export abstract class SelectionMatchFindAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -741,7 +751,8 @@ export class StartFindReplaceAction extends EditorAction {
|
||||
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection,
|
||||
shouldFocus: shouldFocus,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,8 @@ export class FindDecorations implements IDisposable {
|
||||
return this._getDecorationIndex(candidate.id);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
// We don't know the current match position, so returns zero to show '?' in find widget
|
||||
return 0;
|
||||
}
|
||||
|
||||
public setCurrentFindMatch(nextMatch: Range | null): number {
|
||||
|
||||
@@ -251,6 +251,9 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
|
||||
private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
|
||||
if (!this._state.canNavigateBack()) {
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
let prevMatchRange = this._decorations.matchBeforePosition(before);
|
||||
|
||||
@@ -336,6 +339,9 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
|
||||
private _moveToNextMatch(after: Position): void {
|
||||
if (!this._state.canNavigateForward()) {
|
||||
return;
|
||||
}
|
||||
if (this._decorations.getCount() < MATCHES_LIMIT) {
|
||||
let nextMatchRange = this._decorations.matchAfterPosition(after);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { MATCHES_LIMIT } from './findModel';
|
||||
|
||||
export interface FindReplaceStateChangedEvent {
|
||||
moveCursor: boolean;
|
||||
@@ -23,6 +24,7 @@ export interface FindReplaceStateChangedEvent {
|
||||
matchesPosition: boolean;
|
||||
matchesCount: boolean;
|
||||
currentMatch: boolean;
|
||||
loop: boolean;
|
||||
}
|
||||
|
||||
export const enum FindOptionOverride {
|
||||
@@ -45,6 +47,7 @@ export interface INewFindReplaceState {
|
||||
preserveCase?: boolean;
|
||||
preserveCaseOverride?: FindOptionOverride;
|
||||
searchScope?: Range | null;
|
||||
loop?: boolean;
|
||||
}
|
||||
|
||||
function effectiveOptionValue(override: FindOptionOverride, value: boolean): boolean {
|
||||
@@ -74,6 +77,7 @@ export class FindReplaceState extends Disposable {
|
||||
private _matchesPosition: number;
|
||||
private _matchesCount: number;
|
||||
private _currentMatch: Range | null;
|
||||
private _loop: boolean;
|
||||
private readonly _onFindReplaceStateChange = this._register(new Emitter<FindReplaceStateChangedEvent>());
|
||||
|
||||
public get searchString(): string { return this._searchString; }
|
||||
@@ -114,6 +118,7 @@ export class FindReplaceState extends Disposable {
|
||||
this._matchesPosition = 0;
|
||||
this._matchesCount = 0;
|
||||
this._currentMatch = null;
|
||||
this._loop = true;
|
||||
}
|
||||
|
||||
public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void {
|
||||
@@ -131,7 +136,8 @@ export class FindReplaceState extends Disposable {
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: false
|
||||
};
|
||||
let somethingChanged = false;
|
||||
|
||||
@@ -181,7 +187,8 @@ export class FindReplaceState extends Disposable {
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
currentMatch: false
|
||||
currentMatch: false,
|
||||
loop: false
|
||||
};
|
||||
let somethingChanged = false;
|
||||
|
||||
@@ -237,7 +244,13 @@ export class FindReplaceState extends Disposable {
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof newState.loop !== 'undefined') {
|
||||
if (this._loop !== newState.loop) {
|
||||
this._loop = newState.loop;
|
||||
changeEvent.loop = true;
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
// Overrides get set when they explicitly come in and get reset anytime something else changes
|
||||
this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet);
|
||||
this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet);
|
||||
@@ -266,4 +279,17 @@ export class FindReplaceState extends Disposable {
|
||||
this._onFindReplaceStateChange.fire(changeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public canNavigateBack(): boolean {
|
||||
return this.canNavigateInLoop() || (this.matchesPosition !== 1);
|
||||
}
|
||||
|
||||
public canNavigateForward(): boolean {
|
||||
return this.canNavigateInLoop() || (this.matchesPosition < this.matchesCount);
|
||||
}
|
||||
|
||||
private canNavigateInLoop(): boolean {
|
||||
return this._loop || (this.matchesCount >= MATCHES_LIMIT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,18 @@ import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/b
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { Codicon, registerIcon } from 'vs/base/common/codicons';
|
||||
|
||||
const findSelectionIcon = registerIcon('find-selection', Codicon.selection);
|
||||
const findCollapsedIcon = registerIcon('find-collapsed', Codicon.chevronRight);
|
||||
const findExpandedIcon = registerIcon('find-expanded', Codicon.chevronDown);
|
||||
|
||||
export const findCloseIcon = registerIcon('find-close', Codicon.close);
|
||||
export const findReplaceIcon = registerIcon('find-replace', Codicon.replace);
|
||||
export const findReplaceAllIcon = registerIcon('find-replace-all', Codicon.replaceAll);
|
||||
export const findPreviousMatchIcon = registerIcon('find-previous-match', Codicon.arrowUp);
|
||||
export const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDown);
|
||||
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
@@ -152,6 +164,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
themeService: IThemeService,
|
||||
storageService: IStorageService,
|
||||
notificationService: INotificationService,
|
||||
storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
) {
|
||||
super();
|
||||
this._codeEditor = codeEditor;
|
||||
@@ -163,6 +176,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._storageService = storageService;
|
||||
this._notificationService = notificationService;
|
||||
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: ctrlEnterReplaceAllWarningPromptedKey, version: 1 });
|
||||
this._ctrlEnterReplaceAllWarningPrompted = !!storageService.getBoolean(ctrlEnterReplaceAllWarningPromptedKey, StorageScope.GLOBAL);
|
||||
|
||||
this._isVisible = false;
|
||||
@@ -360,6 +374,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
if (e.updateHistory) {
|
||||
this._delayedUpdateHistory();
|
||||
}
|
||||
if (e.loop) {
|
||||
this._updateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private _delayedUpdateHistory() {
|
||||
@@ -405,7 +422,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
this._matchesCount.appendChild(document.createTextNode(label));
|
||||
|
||||
alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString), true);
|
||||
alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString));
|
||||
MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);
|
||||
}
|
||||
|
||||
@@ -455,14 +472,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
let findInputIsNonEmpty = (this._state.searchString.length > 0);
|
||||
let matchesCount = this._state.matchesCount ? true : false;
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateBack());
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateForward());
|
||||
this._replaceBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
this._replaceAllBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
|
||||
dom.toggleClass(this._domNode, 'replaceToggled', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-right', !this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-down', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);
|
||||
|
||||
let canReplace = !this._codeEditor.getOption(EditorOption.readOnly);
|
||||
@@ -984,7 +999,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Previous button
|
||||
this._prevBtn = this._register(new SimpleButton({
|
||||
label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),
|
||||
className: 'codicon codicon-arrow-up',
|
||||
className: findPreviousMatchIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError);
|
||||
}
|
||||
@@ -993,7 +1008,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Next button
|
||||
this._nextBtn = this._register(new SimpleButton({
|
||||
label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),
|
||||
className: 'codicon codicon-arrow-down',
|
||||
className: findNextMatchIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError);
|
||||
}
|
||||
@@ -1011,7 +1026,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
// Toggle selection button
|
||||
this._toggleSelectionFind = this._register(new Checkbox({
|
||||
actionClassName: 'codicon codicon-selection',
|
||||
icon: findSelectionIcon,
|
||||
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
|
||||
isChecked: false
|
||||
}));
|
||||
@@ -1037,7 +1052,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Close button
|
||||
this._closeBtn = this._register(new SimpleButton({
|
||||
label: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand),
|
||||
className: 'codicon codicon-close',
|
||||
className: findCloseIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._state.change({ isRevealed: false, searchScope: null }, false);
|
||||
},
|
||||
@@ -1100,7 +1115,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Replace one button
|
||||
this._replaceBtn = this._register(new SimpleButton({
|
||||
label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),
|
||||
className: 'codicon codicon-replace',
|
||||
className: findReplaceIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._controller.replace();
|
||||
},
|
||||
@@ -1115,7 +1130,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
// Replace all button
|
||||
this._replaceAllBtn = this._register(new SimpleButton({
|
||||
label: NLS_REPLACE_ALL_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceAllAction),
|
||||
className: 'codicon codicon-replace-all',
|
||||
className: findReplaceAllIcon.classNames,
|
||||
onTrigger: () => {
|
||||
this._controller.replaceAll();
|
||||
}
|
||||
@@ -1145,8 +1160,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._showViewZone();
|
||||
}
|
||||
}));
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-down', this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.toggleClass('codicon-chevron-right', !this._isReplaceVisible);
|
||||
this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);
|
||||
|
||||
// Widget
|
||||
@@ -1289,10 +1302,13 @@ export class SimpleButton extends Widget {
|
||||
|
||||
public setExpanded(expanded: boolean): void {
|
||||
this._domNode.setAttribute('aria-expanded', String(!!expanded));
|
||||
}
|
||||
|
||||
public toggleClass(className: string, shouldHaveIt: boolean): void {
|
||||
dom.toggleClass(this._domNode, className, shouldHaveIt);
|
||||
if (expanded) {
|
||||
dom.removeClasses(this._domNode, findCollapsedIcon.classNames);
|
||||
dom.addClasses(this._domNode, findExpandedIcon.classNames);
|
||||
} else {
|
||||
dom.removeClasses(this._domNode, findExpandedIcon.classNames);
|
||||
dom.addClasses(this._domNode, findCollapsedIcon.classNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +276,8 @@ suite('FindController', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
nextMatchFindAction.run(null, editor);
|
||||
startFindReplaceAction.run(null, editor);
|
||||
@@ -301,7 +302,8 @@ suite('FindController', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
updateSearchScope: false,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.equal(findController.getState().searchScope, null);
|
||||
@@ -530,7 +532,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 1, 2, 1));
|
||||
@@ -553,7 +556,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, null);
|
||||
@@ -576,7 +580,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 2, 1, 3));
|
||||
@@ -600,7 +605,8 @@ suite('FindController query options persistence', () => {
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
updateSearchScope: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 6, 2, 1));
|
||||
|
||||
@@ -2089,4 +2089,165 @@ suite('FindModel', () => {
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
});
|
||||
|
||||
findTest('issue #3516: Control behavior of "Next" operations (not looping back to beginning)', (editor, cursor) => {
|
||||
let findState = new FindReplaceState();
|
||||
findState.change({ searchString: 'hello', loop: false }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), false);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), false);
|
||||
|
||||
});
|
||||
|
||||
findTest('issue #3516: Control behavior of "Next" operations (looping back to beginning)', (editor, cursor) => {
|
||||
let findState = new FindReplaceState();
|
||||
findState.change({ searchString: 'hello' }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assert.equal(findState.matchesCount, 5);
|
||||
|
||||
// Test next operations
|
||||
assert.equal(findState.matchesPosition, 0);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToNextMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
// Test previous operations
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 5);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 4);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 3);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 2);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
findModel.moveToPrevMatch();
|
||||
assert.equal(findState.matchesPosition, 1);
|
||||
assert.equal(findState.canNavigateForward(), true);
|
||||
assert.equal(findState.canNavigateBack(), true);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .margin-view-overlays .codicon-chevron-right,
|
||||
.monaco-editor .margin-view-overlays .codicon-chevron-down {
|
||||
.monaco-editor .margin-view-overlays .codicon-folding-expanded,
|
||||
.monaco-editor .margin-view-overlays .codicon-folding-collapsed {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s;
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
|
||||
.monaco-editor .margin-view-overlays:hover .codicon,
|
||||
.monaco-editor .margin-view-overlays .codicon.codicon-chevron-right,
|
||||
.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,
|
||||
.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user