
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { localize } from '../../../../nls.js';
import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { isCancellationError, getErrorMessage, CancellationError } from '../../../../base/common/errors.js';
import { PagedModel, DelayedPagedModel } from '../../../../base/common/paging.js';
import { SortOrder, SortBy, ExtensionGalleryError, ExtensionGalleryErrorCode } from '../../../../platform/extensionManagement/common/extensionManagement.js';
import { EnablementState } from '../../../services/extensionManagement/common/extensionManagement.js';
import { IExtensionManagementServerService, IWorkbenchExtensionManagementService, IWorkbenchExtensionEnablementService } from '../../../services/extensionManagement/common/extensionManagement.service.js';
import { IExtensionRecommendationsService } from '../../../services/extensionRecommendations/common/extensionRecommendations.service.js';
import { areSameExtensions, getExtensionDependencies } from '../../../../platform/extensionManagement/common/extensionManagementUtil.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.service.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.service.js';
import { append, $ } from '../../../../base/browser/dom.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ExtensionResultsListFocused, ExtensionState } from '../common/extensions.js';
import { IExtensionsWorkbenchService } from '../common/extensions.service.js';
import { Query } from '../common/extensionQuery.js';
import { toExtension } from '../../../services/extensions/common/extensions.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.service.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.service.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.service.js';
import { CountBadge } from '../../../../base/browser/ui/countBadge/countBadge.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import '../../../../platform/notification/common/notification.js';
import { INotificationService } from '../../../../platform/notification/common/notification.service.js';
import { ViewPane, ViewPaneShowActions } from '../../../browser/parts/views/viewPane.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.service.js';
import { coalesce, distinct, range } from '../../../../base/common/arrays.js';
import { alert } from '../../../../base/browser/ui/aria/aria.js';
import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
import { ActionRunner } from '../../../../base/common/actions.js';
import { ExtensionIdentifierMap, isLanguagePackExtension, ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
import { createCancelablePromise, ThrottledDelayer } from '../../../../base/common/async.js';
import { IProductService } from '../../../../platform/product/common/productService.service.js';
import { SeverityIcon } from '../../../../base/browser/ui/severityIcon/severityIcon.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { IViewDescriptorService } from '../../../common/views.service.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.service.js';
import { StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IStorageService } from '../../../../platform/storage/common/storage.service.js';
import { IExtensionManifestPropertiesService } from '../../../services/extensions/common/extensionManifestPropertiesService.service.js';
import { isVirtualWorkspace } from '../../../../platform/workspace/common/virtualWorkspace.js';
import { IWorkspaceTrustManagementService } from '../../../../platform/workspace/common/workspaceTrust.service.js';
import { ILogService } from '../../../../platform/log/common/log.service.js';
import { isOfflineError } from '../../../../base/parts/request/common/request.js';
import { defaultCountBadgeStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { Extensions } from '../../../services/extensionManagement/common/extensionFeatures.js';
import { IExtensionFeaturesManagementService } from '../../../services/extensionManagement/common/extensionFeatures.service.js';
import { isString } from '../../../../base/common/types.js';
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.service.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.service.js';
import { ExtensionsList } from './extensionsViewer.js';
import Severity$1 from '../../../../base/common/severity.js';

var ExtensionsListView_1;
const NONE_CATEGORY = "none";
class ExtensionsViewState extends Disposable {
    constructor() {
        super(...arguments);
        this._onFocus = this._register(( new Emitter()));
        this.onFocus = this._onFocus.event;
        this._onBlur = this._register(( new Emitter()));
        this.onBlur = this._onBlur.event;
        this.currentlyFocusedItems = [];
        this.filters = {};
    }
    onFocusChange(extensions) {
        this.currentlyFocusedItems.forEach(extension => this._onBlur.fire(extension));
        this.currentlyFocusedItems = extensions;
        this.currentlyFocusedItems.forEach(extension => this._onFocus.fire(extension));
    }
}
var LocalSortBy;
(function(LocalSortBy) {
    LocalSortBy["UpdateDate"] = "UpdateDate";
})(LocalSortBy || (LocalSortBy = {}));
function isLocalSortBy(value) {
    switch (value) {
    case LocalSortBy.UpdateDate:
        return true;
    }
}
class AbstractExtensionsListView extends ViewPane {}
let ExtensionsListView = class ExtensionsListView extends AbstractExtensionsListView {
    static {
        ExtensionsListView_1 = this;
    }
    static {
        this.RECENT_UPDATE_DURATION = 7 * 24 * 60 * 60 * 1000;
    }
    constructor(
        options,
        viewletViewOptions,
        notificationService,
        keybindingService,
        contextMenuService,
        instantiationService,
        themeService,
        extensionService,
        extensionsWorkbenchService,
        extensionRecommendationsService,
        telemetryService,
        hoverService,
        configurationService,
        contextService,
        extensionManagementServerService,
        extensionManifestPropertiesService,
        extensionManagementService,
        workspaceService,
        productService,
        contextKeyService,
        viewDescriptorService,
        openerService,
        storageService,
        workspaceTrustManagementService,
        extensionEnablementService,
        extensionFeaturesManagementService,
        uriIdentityService,
        logService
    ) {
        super({
            ...viewletViewOptions,
            showActions: ViewPaneShowActions.Always,
            maximumBodySize: options.flexibleHeight ? (storageService.getNumber(`${viewletViewOptions.id}.size`, StorageScope.PROFILE, 0) ? undefined : 0) : undefined
        }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);
        this.options = options;
        this.notificationService = notificationService;
        this.extensionService = extensionService;
        this.extensionsWorkbenchService = extensionsWorkbenchService;
        this.extensionRecommendationsService = extensionRecommendationsService;
        this.telemetryService = telemetryService;
        this.contextService = contextService;
        this.extensionManagementServerService = extensionManagementServerService;
        this.extensionManifestPropertiesService = extensionManifestPropertiesService;
        this.extensionManagementService = extensionManagementService;
        this.workspaceService = workspaceService;
        this.productService = productService;
        this.storageService = storageService;
        this.workspaceTrustManagementService = workspaceTrustManagementService;
        this.extensionEnablementService = extensionEnablementService;
        this.extensionFeaturesManagementService = extensionFeaturesManagementService;
        this.uriIdentityService = uriIdentityService;
        this.logService = logService;
        this.list = null;
        this.queryRequest = null;
        this.contextMenuActionRunner = this._register(( new ActionRunner()));
        if (this.options.onDidChangeTitle) {
            this._register(this.options.onDidChangeTitle(title => this.updateTitle(title)));
        }
        this._register(this.contextMenuActionRunner.onDidRun((
            {
                error
            }
        ) => error && this.notificationService.error(error)));
        this.registerActions();
    }
    registerActions() {}
    renderHeader(container) {
        container.classList.add("extension-view-header");
        super.renderHeader(container);
        if (!this.options.hideBadge) {
            this.badge = this._register(( new CountBadge(append(container, $(".count-badge-wrapper")), {}, defaultCountBadgeStyles)));
        }
    }
    renderBody(container) {
        super.renderBody(container);
        const messageContainer = append(container, $(".message-container"));
        const messageSeverityIcon = append(messageContainer, $(""));
        const messageBox = append(messageContainer, $(".message"));
        const extensionsList = append(container, $(".extensions-list"));
        this.extensionsViewState = this._register(( new ExtensionsViewState()));
        this.list = this._register(
            this.instantiationService.createInstance(ExtensionsList, extensionsList, this.id, {}, this.extensionsViewState)
        ).list;
        ExtensionResultsListFocused.bindTo(this.list.contextKeyService);
        this._register(
            this.list.onDidChangeFocus(e => this.extensionsViewState?.onFocusChange(coalesce(e.elements)), this)
        );
        this.bodyTemplate = {
            extensionsList,
            messageBox,
            messageContainer,
            messageSeverityIcon
        };
        if (this.queryResult) {
            this.setModel(this.queryResult.model);
        }
    }
    layoutBody(height, width) {
        super.layoutBody(height, width);
        if (this.bodyTemplate) {
            this.bodyTemplate.extensionsList.style.height = height + "px";
        }
        this.list?.layout(height, width);
    }
    async show(query, refresh) {
        if (this.queryRequest) {
            if (!refresh && this.queryRequest.query === query) {
                return this.queryRequest.request;
            }
            this.queryRequest.request.cancel();
            this.queryRequest = null;
        }
        if (this.queryResult) {
            this.queryResult.disposables.dispose();
            this.queryResult = undefined;
            if (this.extensionsViewState) {
                this.extensionsViewState.filters = {};
            }
        }
        const parsedQuery = Query.parse(query);
        const options = {
            sortOrder: SortOrder.Default
        };
        switch (parsedQuery.sortBy) {
        case "installs":
            options.sortBy = SortBy.InstallCount;
            break;
        case "rating":
            options.sortBy = SortBy.WeightedRating;
            break;
        case "name":
            options.sortBy = SortBy.Title;
            break;
        case "publishedDate":
            options.sortBy = SortBy.PublishedDate;
            break;
        case "updateDate":
            options.sortBy = LocalSortBy.UpdateDate;
            break;
        }
        const request = createCancelablePromise(async token => {
            try {
                this.queryResult = await this.query(parsedQuery, options, token);
                const model = this.queryResult.model;
                this.setModel(model, this.queryResult.message);
                if (this.queryResult.onDidChangeModel) {
                    this.queryResult.disposables.add(this.queryResult.onDidChangeModel(model => {
                        if (this.queryResult) {
                            this.queryResult.model = model;
                            this.updateModel(model);
                        }
                    }));
                }
                return model;
            } catch (e) {
                const model = ( new PagedModel([]));
                if (!isCancellationError(e)) {
                    this.logService.error(e);
                    this.setModel(model, this.getMessage(e));
                }
                return this.list ? this.list.model : model;
            }
        });
        request.finally(() => this.queryRequest = null);
        this.queryRequest = {
            query,
            request
        };
        return request;
    }
    count() {
        return this.queryResult?.model.length ?? 0;
    }
    showEmptyModel() {
        const emptyModel = ( new PagedModel([]));
        this.setModel(emptyModel);
        return Promise.resolve(emptyModel);
    }
    async query(query, options, token) {
        const idRegex = /@id:(([a-z0-9A-Z][a-z0-9\-A-Z]*)\.([a-z0-9A-Z][a-z0-9\-A-Z]*))/g;
        const ids = [];
        let idMatch;
        while ((idMatch = idRegex.exec(query.value)) !== null) {
            const name = idMatch[1];
            ids.push(name);
        }
        if (ids.length) {
            const model = await this.queryByIds(ids, options, token);
            return {
                model,
                disposables: ( new DisposableStore())
            };
        }
        if (ExtensionsListView_1.isLocalExtensionsQuery(query.value, query.sortBy)) {
            return this.queryLocal(query, options);
        }
        if (ExtensionsListView_1.isSearchPopularQuery(query.value)) {
            query.value = query.value.replace("@popular", "");
            options.sortBy = !options.sortBy ? SortBy.InstallCount : options.sortBy;
        } else if (ExtensionsListView_1.isSearchRecentlyPublishedQuery(query.value)) {
            query.value = query.value.replace("@recentlyPublished", "");
            options.sortBy = !options.sortBy ? SortBy.PublishedDate : options.sortBy;
        }
        const galleryQueryOptions = {
            ...options,
            sortBy: isLocalSortBy(options.sortBy) ? undefined : options.sortBy
        };
        return this.queryGallery(query, galleryQueryOptions, token);
    }
    async queryByIds(ids, options, token) {
        const idsSet = ids.reduce((result, id) => {
            result.add(id.toLowerCase());
            return result;
        }, ( new Set()));
        const result = (await this.extensionsWorkbenchService.queryLocal(this.options.server)).filter(e => ( idsSet.has(e.identifier.id.toLowerCase())));
        const galleryIds = result.length ? ids.filter(id => result.every(r => !areSameExtensions(r.identifier, {
            id
        }))) : ids;
        if (galleryIds.length) {
            const galleryResult = await this.extensionsWorkbenchService.getExtensions(( galleryIds.map(id => ({
                id
            }))), {
                source: "queryById"
            }, token);
            result.push(...galleryResult);
        }
        return ( new PagedModel(result));
    }
    async queryLocal(query, options) {
        const local = await this.extensionsWorkbenchService.queryLocal(this.options.server);
        let {
            extensions,
            canIncludeInstalledExtensions,
            description
        } = await this.filterLocal(local, this.extensionService.extensions, query, options);
        const disposables = ( new DisposableStore());
        const onDidChangeModel = disposables.add(( new Emitter()));
        if (canIncludeInstalledExtensions) {
            let isDisposed = false;
            disposables.add(toDisposable(() => isDisposed = true));
            disposables.add(Event.debounce(Event.any(Event.filter(
                this.extensionsWorkbenchService.onChange,
                e => e?.state === ExtensionState.Installed
            ), this.extensionService.onDidChangeExtensions), () => undefined)(async () => {
                const local = this.options.server ? this.extensionsWorkbenchService.installed.filter(e => e.server === this.options.server) : this.extensionsWorkbenchService.local;
                const {
                    extensions: newExtensions
                } = await this.filterLocal(local, this.extensionService.extensions, query, options);
                if (!isDisposed) {
                    const mergedExtensions = this.mergeAddedExtensions(extensions, newExtensions);
                    if (mergedExtensions) {
                        extensions = mergedExtensions;
                        onDidChangeModel.fire(( new PagedModel(extensions)));
                    }
                }
            }));
        }
        return {
            model: ( new PagedModel(extensions)),
            message: description ? {
                text: description,
                severity: Severity$1.Info
            } : undefined,
            onDidChangeModel: onDidChangeModel.event,
            disposables
        };
    }
    async filterLocal(local, runningExtensions, query, options) {
        const value = query.value;
        let extensions = [];
        let description;
        const includeBuiltin = /@builtin/i.test(value);
        const canIncludeInstalledExtensions = !includeBuiltin;
        if (/@installed/i.test(value)) {
            extensions = this.filterInstalledExtensions(local, runningExtensions, query, options);
        } else if (/@outdated/i.test(value)) {
            extensions = this.filterOutdatedExtensions(local, query, options);
        } else if (/@disabled/i.test(value)) {
            extensions = this.filterDisabledExtensions(local, runningExtensions, query, options, includeBuiltin);
        } else if (/@enabled/i.test(value)) {
            extensions = this.filterEnabledExtensions(local, runningExtensions, query, options, includeBuiltin);
        } else if (/@workspaceUnsupported/i.test(value)) {
            extensions = this.filterWorkspaceUnsupportedExtensions(local, query, options);
        } else if (/@deprecated/i.test(query.value)) {
            extensions = await this.filterDeprecatedExtensions(local, query, options);
        } else if (/@recentlyUpdated/i.test(query.value)) {
            extensions = this.filterRecentlyUpdatedExtensions(local, query, options);
        } else if (/@restartrequired/i.test(query.value)) {
            extensions = this.filterRestartRequiredExtensions(local, query, options);
        } else if (/@contribute:/i.test(query.value)) {
            extensions = this.filterExtensionsByFeature(local, query);
        } else if (includeBuiltin) {
            extensions = this.filterBuiltinExtensions(local, query, options);
        }
        return {
            extensions,
            canIncludeInstalledExtensions,
            description
        };
    }
    filterBuiltinExtensions(local, query, options) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        value = value.replaceAll(/@builtin/gi, "").replaceAll(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const result = local.filter(
            e => e.isBuiltin && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories)
        );
        return this.sortExtensions(result, options);
    }
    filterExtensionByCategory(e, includedCategories, excludedCategories) {
        if (!includedCategories.length && !excludedCategories.length) {
            return true;
        }
        if (e.categories.length) {
            if (excludedCategories.length && ( e.categories.some(category => excludedCategories.includes(category.toLowerCase())))) {
                return false;
            }
            return ( e.categories.some(category => includedCategories.includes(category.toLowerCase())));
        } else {
            return includedCategories.includes(NONE_CATEGORY);
        }
    }
    parseCategories(value) {
        const includedCategories = [];
        const excludedCategories = [];
        value = value.replace(
            /\bcategory:("([^"]*)"|([^"]\S*))(\s+|\b|$)/g,
            (_, quotedCategory, category) => {
                const entry = (category || quotedCategory || "").toLowerCase();
                if (entry.startsWith("-")) {
                    if (excludedCategories.indexOf(entry) === -1) {
                        excludedCategories.push(entry);
                    }
                } else {
                    if (includedCategories.indexOf(entry) === -1) {
                        includedCategories.push(entry);
                    }
                }
                return "";
            }
        );
        return {
            value,
            includedCategories,
            excludedCategories
        };
    }
    filterInstalledExtensions(local, runningExtensions, query, options) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        value = value.replace(/@installed/g, "").replace(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const matchingText = e => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1 || e.description.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories);
        let result;
        if (options.sortBy !== undefined) {
            result = local.filter(e => !e.isBuiltin && matchingText(e));
            result = this.sortExtensions(result, options);
        } else {
            result = local.filter(
                e => (!e.isBuiltin || e.outdated || e.runtimeState !== undefined) && matchingText(e)
            );
            const runningExtensionsById = runningExtensions.reduce((result, e) => {
                result.set(e.identifier.value, e);
                return result;
            }, ( new ExtensionIdentifierMap()));
            const defaultSort = (e1, e2) => {
                const running1 = runningExtensionsById.get(e1.identifier.id);
                const isE1Running = !!running1 && this.extensionManagementServerService.getExtensionManagementServer(toExtension(running1)) === e1.server;
                const running2 = runningExtensionsById.get(e2.identifier.id);
                const isE2Running = running2 && this.extensionManagementServerService.getExtensionManagementServer(toExtension(running2)) === e2.server;
                if ((isE1Running && isE2Running)) {
                    return e1.displayName.localeCompare(e2.displayName);
                }
                const isE1LanguagePackExtension = e1.local && isLanguagePackExtension(e1.local.manifest);
                const isE2LanguagePackExtension = e2.local && isLanguagePackExtension(e2.local.manifest);
                if (!isE1Running && !isE2Running) {
                    if (isE1LanguagePackExtension) {
                        return -1;
                    }
                    if (isE2LanguagePackExtension) {
                        return 1;
                    }
                    return e1.displayName.localeCompare(e2.displayName);
                }
                if ((isE1Running && isE2LanguagePackExtension) || (isE2Running && isE1LanguagePackExtension)) {
                    return e1.displayName.localeCompare(e2.displayName);
                }
                return isE1Running ? -1 : 1;
            };
            const incompatible = [];
            const deprecated = [];
            const outdated = [];
            const actionRequired = [];
            const noActionRequired = [];
            for (const e of result) {
                if (e.enablementState === EnablementState.DisabledByInvalidExtension) {
                    incompatible.push(e);
                } else if (e.deprecationInfo) {
                    deprecated.push(e);
                } else if (e.outdated && this.extensionEnablementService.isEnabledEnablementState(e.enablementState)) {
                    outdated.push(e);
                } else if (e.runtimeState) {
                    actionRequired.push(e);
                } else {
                    noActionRequired.push(e);
                }
            }
            result = [
                ...incompatible.sort(defaultSort),
                ...deprecated.sort(defaultSort),
                ...outdated.sort(defaultSort),
                ...actionRequired.sort(defaultSort),
                ...noActionRequired.sort(defaultSort)
            ];
        }
        return result;
    }
    filterOutdatedExtensions(local, query, options) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        value = value.replace(/@outdated/g, "").replace(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const result = local.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)).filter(
            extension => extension.outdated && (extension.name.toLowerCase().indexOf(value) > -1 || extension.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(extension, includedCategories, excludedCategories)
        );
        return this.sortExtensions(result, options);
    }
    filterDisabledExtensions(local, runningExtensions, query, options, includeBuiltin) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        value = value.replaceAll(/@disabled|@builtin/gi, "").replaceAll(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        if (includeBuiltin) {
            local = local.filter(e => e.isBuiltin);
        }
        const result = local.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)).filter(e => runningExtensions.every(r => !areSameExtensions({
            id: r.identifier.value,
            uuid: r.uuid
        }, e.identifier)) && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories));
        return this.sortExtensions(result, options);
    }
    filterEnabledExtensions(local, runningExtensions, query, options, includeBuiltin) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        value = value ? value.replaceAll(/@enabled|@builtin/gi, "").replaceAll(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase() : "";
        local = local.filter(e => e.isBuiltin === includeBuiltin);
        const result = local.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)).filter(e => ( runningExtensions.some(r => areSameExtensions({
            id: r.identifier.value,
            uuid: r.uuid
        }, e.identifier))) && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories));
        return this.sortExtensions(result, options);
    }
    filterWorkspaceUnsupportedExtensions(local, query, options) {
        const queryString = query.value;
        const match = queryString.match(
            /^\s*@workspaceUnsupported(?::(untrusted|virtual)(Partial)?)?(?:\s+([^\s]*))?/i
        );
        if (!match) {
            return [];
        }
        const type = match[1]?.toLowerCase();
        const partial = !!match[2];
        const nameFilter = match[3]?.toLowerCase();
        if (nameFilter) {
            local = local.filter(
                extension => extension.name.toLowerCase().indexOf(nameFilter) > -1 || extension.displayName.toLowerCase().indexOf(nameFilter) > -1
            );
        }
        const hasVirtualSupportType = (extension, supportType) => {
            return extension.local && this.extensionManifestPropertiesService.getExtensionVirtualWorkspaceSupportType(extension.local.manifest) === supportType;
        };
        const hasRestrictedSupportType = (extension, supportType) => {
            if (!extension.local) {
                return false;
            }
            const enablementState = this.extensionEnablementService.getEnablementState(extension.local);
            if (enablementState !== EnablementState.EnabledGlobally && enablementState !== EnablementState.EnabledWorkspace && enablementState !== EnablementState.DisabledByTrustRequirement && enablementState !== EnablementState.DisabledByExtensionDependency) {
                return false;
            }
            if (this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.local.manifest) === supportType) {
                return true;
            }
            if (supportType === false) {
                const dependencies = getExtensionDependencies(( local.map(ext => ext.local)), extension.local);
                return ( dependencies.some(
                    ext => this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(ext.manifest) === supportType
                ));
            }
            return false;
        };
        const inVirtualWorkspace = isVirtualWorkspace(this.workspaceService.getWorkspace());
        const inRestrictedWorkspace = !this.workspaceTrustManagementService.isWorkspaceTrusted();
        if (type === "virtual") {
            local = local.filter(
                extension => inVirtualWorkspace && hasVirtualSupportType(extension, partial ? "limited" : false) && !(inRestrictedWorkspace && hasRestrictedSupportType(extension, false))
            );
        } else if (type === "untrusted") {
            local = local.filter(
                extension => hasRestrictedSupportType(extension, partial ? "limited" : false) && !(inVirtualWorkspace && hasVirtualSupportType(extension, false))
            );
        } else {
            local = local.filter(
                extension => inVirtualWorkspace && !hasVirtualSupportType(extension, true) || inRestrictedWorkspace && !hasRestrictedSupportType(extension, true)
            );
        }
        return this.sortExtensions(local, options);
    }
    async filterDeprecatedExtensions(local, query, options) {
        const value = query.value.replace(/@deprecated/g, "").replace(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest();
        const deprecatedExtensionIds = ( Object.keys(extensionsControlManifest.deprecated));
        local = local.filter(
            e => deprecatedExtensionIds.includes(e.identifier.id) && (!value || e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)
        );
        return this.sortExtensions(local, options);
    }
    filterRecentlyUpdatedExtensions(local, query, options) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        const currentTime = Date.now();
        local = local.filter(
            e => !e.isBuiltin && !e.outdated && e.local?.updated && e.local?.installedTimestamp !== undefined && currentTime - e.local.installedTimestamp < ExtensionsListView_1.RECENT_UPDATE_DURATION
        );
        value = value.replace(/@recentlyUpdated/g, "").replace(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const result = local.filter(
            e => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories)
        );
        options.sortBy = options.sortBy ?? LocalSortBy.UpdateDate;
        return this.sortExtensions(result, options);
    }
    filterRestartRequiredExtensions(local, query, options) {
        let {
            value,
            includedCategories,
            excludedCategories
        } = this.parseCategories(query.value);
        local = local.filter(e => e.runtimeState !== undefined);
        value = value.replace(/@restartrequired/gi, "").replace(/@sort:(\w+)(-\w*)?/g, "").trim().toLowerCase();
        const result = local.filter(
            e => (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1) && this.filterExtensionByCategory(e, includedCategories, excludedCategories)
        );
        return this.sortExtensions(result, options);
    }
    filterExtensionsByFeature(local, query) {
        const value = query.value.replace(/@contribute:/g, "").trim();
        const featureId = value.split(" ")[0];
        const feature = ( Registry.as(Extensions.ExtensionFeaturesRegistry)).getExtensionFeature(featureId);
        if (!feature) {
            return [];
        }
        if (this.extensionsViewState) {
            this.extensionsViewState.filters.featureId = featureId;
        }
        const renderer = feature.renderer ? this.instantiationService.createInstance(feature.renderer) : undefined;
        try {
            const result = [];
            for (const e of local) {
                if (!e.local) {
                    continue;
                }
                const accessData = this.extensionFeaturesManagementService.getAccessData(( new ExtensionIdentifier(e.identifier.id)), featureId);
                const shouldRender = renderer?.shouldRender(e.local.manifest);
                if (accessData || shouldRender) {
                    result.push([e, accessData?.accessTimes.length ?? 0]);
                }
            }
            return ( result.sort(([, a], [, b]) => b - a).map(([e]) => e));
        } finally {
            renderer?.dispose();
        }
    }
    mergeAddedExtensions(extensions, newExtensions) {
        const oldExtensions = [...extensions];
        const findPreviousExtensionIndex = from => {
            let index = -1;
            const previousExtensionInNew = newExtensions[from];
            if (previousExtensionInNew) {
                index = oldExtensions.findIndex(e => areSameExtensions(e.identifier, previousExtensionInNew.identifier));
                if (index === -1) {
                    return findPreviousExtensionIndex(from - 1);
                }
            }
            return index;
        };
        let hasChanged = false;
        for (let index = 0; index < newExtensions.length; index++) {
            const extension = newExtensions[index];
            if (extensions.every(r => !areSameExtensions(r.identifier, extension.identifier))) {
                hasChanged = true;
                extensions.splice(findPreviousExtensionIndex(index - 1) + 1, 0, extension);
            }
        }
        return hasChanged ? extensions : undefined;
    }
    async queryGallery(query, options, token) {
        const hasUserDefinedSortOrder = options.sortBy !== undefined;
        if (!hasUserDefinedSortOrder && !query.value.trim()) {
            options.sortBy = SortBy.InstallCount;
        }
        if (this.isRecommendationsQuery(query)) {
            const model = await this.queryRecommendations(query, options, token);
            return {
                model,
                disposables: ( new DisposableStore())
            };
        }
        const text = query.value;
        if (!text) {
            options.source = "viewlet";
            const pager = await this.extensionsWorkbenchService.queryGallery(options, token);
            return {
                model: ( new PagedModel(pager)),
                disposables: ( new DisposableStore())
            };
        }
        if (/\bext:([^\s]+)\b/g.test(text)) {
            options.text = text;
            options.source = "file-extension-tags";
            const pager = await this.extensionsWorkbenchService.queryGallery(options, token);
            return {
                model: ( new PagedModel(pager)),
                disposables: ( new DisposableStore())
            };
        }
        options.text = text.substring(0, 350);
        options.source = "searchText";
        if (hasUserDefinedSortOrder || /\b(category|tag):([^\s]+)\b/gi.test(text) || /\bfeatured(\s+|\b|$)/gi.test(text)) {
            const pager = await this.extensionsWorkbenchService.queryGallery(options, token);
            return {
                model: ( new PagedModel(pager)),
                disposables: ( new DisposableStore())
            };
        }
        try {
            const [pager, preferredExtensions] = await Promise.all([
                this.extensionsWorkbenchService.queryGallery(options, token),
                this.getPreferredExtensions(options.text.toLowerCase(), token).catch(() => [])
            ]);
            const model = preferredExtensions.length ? ( new PreferredExtensionsPagedModel(preferredExtensions, pager)) : ( new PagedModel(pager));
            return {
                model,
                disposables: ( new DisposableStore())
            };
        } catch (error) {
            if (isCancellationError(error)) {
                throw error;
            }
            if (!(error instanceof ExtensionGalleryError)) {
                throw error;
            }
            const searchText = options.text.toLowerCase();
            const localExtensions = this.extensionsWorkbenchService.local.filter(
                e => !e.isBuiltin && (e.name.toLowerCase().indexOf(searchText) > -1 || e.displayName.toLowerCase().indexOf(searchText) > -1 || e.description.toLowerCase().indexOf(searchText) > -1)
            );
            if (localExtensions.length) {
                const message = this.getMessage(error);
                return {
                    model: ( new PagedModel(localExtensions)),
                    disposables: ( new DisposableStore()),
                    message: {
                        text: ( localize(9303, "{0} Showing local extensions.", message.text)),
                        severity: message.severity
                    }
                };
            }
            throw error;
        }
    }
    async getPreferredExtensions(searchText, token) {
        const preferredExtensions = this.extensionsWorkbenchService.local.filter(
            e => !e.isBuiltin && (e.name.toLowerCase().indexOf(searchText) > -1 || e.displayName.toLowerCase().indexOf(searchText) > -1 || e.description.toLowerCase().indexOf(searchText) > -1)
        );
        const preferredExtensionUUIDs = ( new Set());
        if (preferredExtensions.length) {
            const extesionsToFetch = [];
            for (const extension of preferredExtensions) {
                if (extension.identifier.uuid) {
                    preferredExtensionUUIDs.add(extension.identifier.uuid);
                }
                if (!extension.gallery && extension.identifier.uuid) {
                    extesionsToFetch.push(extension.identifier);
                }
            }
            if (extesionsToFetch.length) {
                this.extensionsWorkbenchService.getExtensions(extesionsToFetch, CancellationToken.None).catch(e => null );
            }
        }
        const preferredResults = [];
        try {
            const manifest = await this.extensionManagementService.getExtensionsControlManifest();
            if (Array.isArray(manifest.search)) {
                for (const s of manifest.search) {
                    if (s.query && s.query.toLowerCase() === searchText && Array.isArray(s.preferredResults)) {
                        preferredResults.push(...s.preferredResults);
                        break;
                    }
                }
            }
            if (preferredResults.length) {
                const result = await this.extensionsWorkbenchService.getExtensions(( preferredResults.map(id => ({
                    id
                }))), token);
                for (const extension of result) {
                    if (extension.identifier.uuid && !( preferredExtensionUUIDs.has(extension.identifier.uuid))) {
                        preferredExtensions.push(extension);
                    }
                }
            }
        } catch (e) {
            this.logService.warn("Failed to get preferred results from the extensions control manifest.", e);
        }
        return preferredExtensions;
    }
    sortExtensions(extensions, options) {
        switch (options.sortBy) {
        case SortBy.InstallCount:
            extensions = extensions.sort(
                (e1, e2) => typeof e2.installCount === "number" && typeof e1.installCount === "number" ? e2.installCount - e1.installCount : NaN
            );
            break;
        case LocalSortBy.UpdateDate:
            extensions = extensions.sort(
                (e1, e2) => typeof e2.local?.installedTimestamp === "number" && typeof e1.local?.installedTimestamp === "number" ? e2.local.installedTimestamp - e1.local.installedTimestamp : typeof e2.local?.installedTimestamp === "number" ? 1 : typeof e1.local?.installedTimestamp === "number" ? -1 : NaN
            );
            break;
        case SortBy.AverageRating:
        case SortBy.WeightedRating:
            extensions = extensions.sort(
                (e1, e2) => typeof e2.rating === "number" && typeof e1.rating === "number" ? e2.rating - e1.rating : NaN
            );
            break;
        default:
            extensions = extensions.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName));
            break;
        }
        if (options.sortOrder === SortOrder.Descending) {
            extensions = extensions.reverse();
        }
        return extensions;
    }
    isRecommendationsQuery(query) {
        return ExtensionsListView_1.isWorkspaceRecommendedExtensionsQuery(query.value) || ExtensionsListView_1.isKeymapsRecommendedExtensionsQuery(query.value) || ExtensionsListView_1.isLanguageRecommendedExtensionsQuery(query.value) || ExtensionsListView_1.isExeRecommendedExtensionsQuery(query.value) || ExtensionsListView_1.isRemoteRecommendedExtensionsQuery(query.value) || /@recommended:all/i.test(query.value) || ExtensionsListView_1.isSearchRecommendedExtensionsQuery(query.value) || ExtensionsListView_1.isRecommendedExtensionsQuery(query.value);
    }
    async queryRecommendations(query, options, token) {
        if (ExtensionsListView_1.isWorkspaceRecommendedExtensionsQuery(query.value)) {
            return this.getWorkspaceRecommendationsModel(query, options, token);
        }
        if (ExtensionsListView_1.isKeymapsRecommendedExtensionsQuery(query.value)) {
            return this.getKeymapRecommendationsModel(query, options, token);
        }
        if (ExtensionsListView_1.isLanguageRecommendedExtensionsQuery(query.value)) {
            return this.getLanguageRecommendationsModel(query, options, token);
        }
        if (ExtensionsListView_1.isExeRecommendedExtensionsQuery(query.value)) {
            return this.getExeRecommendationsModel(query, options, token);
        }
        if (ExtensionsListView_1.isRemoteRecommendedExtensionsQuery(query.value)) {
            return this.getRemoteRecommendationsModel(query, options, token);
        }
        if (/@recommended:all/i.test(query.value)) {
            return this.getAllRecommendationsModel(options, token);
        }
        if (ExtensionsListView_1.isSearchRecommendedExtensionsQuery(query.value) || (ExtensionsListView_1.isRecommendedExtensionsQuery(query.value) && options.sortBy !== undefined)) {
            return this.searchRecommendations(query, options, token);
        }
        if (ExtensionsListView_1.isRecommendedExtensionsQuery(query.value)) {
            return this.getOtherRecommendationsModel(query, options, token);
        }
        return ( new PagedModel([]));
    }
    async getInstallableRecommendations(recommendations, options, token) {
        const result = [];
        if (recommendations.length) {
            const galleryExtensions = [];
            const resourceExtensions = [];
            for (const recommendation of recommendations) {
                if (typeof recommendation === "string") {
                    galleryExtensions.push(recommendation);
                } else {
                    resourceExtensions.push(recommendation);
                }
            }
            if (galleryExtensions.length) {
                try {
                    const extensions = await this.extensionsWorkbenchService.getExtensions(( galleryExtensions.map(id => ({
                        id
                    }))), {
                        source: options.source
                    }, token);
                    for (const extension of extensions) {
                        if (extension.gallery && !extension.deprecationInfo && (await this.extensionManagementService.canInstall(extension.gallery)) === true) {
                            result.push(extension);
                        }
                    }
                } catch (error) {
                    if (!resourceExtensions.length || !this.isOfflineError(error)) {
                        throw error;
                    }
                }
            }
            if (resourceExtensions.length) {
                const extensions = await this.extensionsWorkbenchService.getResourceExtensions(resourceExtensions, true);
                for (const extension of extensions) {
                    if ((await this.extensionsWorkbenchService.canInstall(extension)) === true) {
                        result.push(extension);
                    }
                }
            }
        }
        return result;
    }
    async getWorkspaceRecommendations() {
        const recommendations = await this.extensionRecommendationsService.getWorkspaceRecommendations();
        const {
            important
        } = await this.extensionRecommendationsService.getConfigBasedRecommendations();
        for (const configBasedRecommendation of important) {
            if (!recommendations.find(extensionId => extensionId === configBasedRecommendation)) {
                recommendations.push(configBasedRecommendation);
            }
        }
        return recommendations;
    }
    async getWorkspaceRecommendationsModel(query, options, token) {
        const recommendations = await this.getWorkspaceRecommendations();
        const installableRecommendations = (await this.getInstallableRecommendations(recommendations, {
            ...options,
            source: "recommendations-workspace"
        }, token));
        return ( new PagedModel(installableRecommendations));
    }
    async getKeymapRecommendationsModel(query, options, token) {
        const value = query.value.replace(/@recommended:keymaps/g, "").trim().toLowerCase();
        const recommendations = this.extensionRecommendationsService.getKeymapRecommendations();
        const installableRecommendations = (await this.getInstallableRecommendations(recommendations, {
            ...options,
            source: "recommendations-keymaps"
        }, token)).filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1);
        return ( new PagedModel(installableRecommendations));
    }
    async getLanguageRecommendationsModel(query, options, token) {
        const value = query.value.replace(/@recommended:languages/g, "").trim().toLowerCase();
        const recommendations = this.extensionRecommendationsService.getLanguageRecommendations();
        const installableRecommendations = (await this.getInstallableRecommendations(recommendations, {
            ...options,
            source: "recommendations-languages"
        }, token)).filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1);
        return ( new PagedModel(installableRecommendations));
    }
    async getRemoteRecommendationsModel(query, options, token) {
        const value = query.value.replace(/@recommended:remotes/g, "").trim().toLowerCase();
        const recommendations = this.extensionRecommendationsService.getRemoteRecommendations();
        const installableRecommendations = (await this.getInstallableRecommendations(recommendations, {
            ...options,
            source: "recommendations-remotes"
        }, token)).filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1);
        return ( new PagedModel(installableRecommendations));
    }
    async getExeRecommendationsModel(query, options, token) {
        const exe = query.value.replace(/@exe:/g, "").trim().toLowerCase();
        const {
            important,
            others
        } = await this.extensionRecommendationsService.getExeBasedRecommendations(exe.startsWith("\"") ? exe.substring(1, exe.length - 1) : exe);
        const installableRecommendations = await this.getInstallableRecommendations([...important, ...others], {
            ...options,
            source: "recommendations-exe"
        }, token);
        return ( new PagedModel(installableRecommendations));
    }
    async getOtherRecommendationsModel(query, options, token) {
        const otherRecommendations = await this.getOtherRecommendations();
        const installableRecommendations = await this.getInstallableRecommendations(otherRecommendations, {
            ...options,
            source: "recommendations-other",
            sortBy: undefined
        }, token);
        const result = coalesce(( otherRecommendations.map(
            id => installableRecommendations.find(i => areSameExtensions(i.identifier, {
                id
            }))
        )));
        return ( new PagedModel(result));
    }
    async getOtherRecommendations() {
        const local = ( (await this.extensionsWorkbenchService.queryLocal(this.options.server)).map(e => e.identifier.id.toLowerCase()));
        const workspaceRecommendations = ( (await this.getWorkspaceRecommendations()).map(
            extensionId => isString(extensionId) ? extensionId.toLowerCase() : extensionId
        ));
        return distinct((await Promise.all([
        this.extensionRecommendationsService.getImportantRecommendations(), this.extensionRecommendationsService.getFileBasedRecommendations(), this.extensionRecommendationsService.getOtherRecommendations()])).flat().filter(
            extensionId => !local.includes(extensionId.toLowerCase()) && !workspaceRecommendations.includes(extensionId.toLowerCase())
        ), extensionId => extensionId.toLowerCase());
    }
    async getAllRecommendationsModel(options, token) {
        const localExtensions = await this.extensionsWorkbenchService.queryLocal(this.options.server);
        const localExtensionIds = ( localExtensions.map(e => e.identifier.id.toLowerCase()));
        const allRecommendations = distinct((await Promise.all([
        this.getWorkspaceRecommendations(), this.extensionRecommendationsService.getImportantRecommendations(), this.extensionRecommendationsService.getFileBasedRecommendations(), this.extensionRecommendationsService.getOtherRecommendations()])).flat().filter(extensionId => {
            if (isString(extensionId)) {
                return !localExtensionIds.includes(extensionId.toLowerCase());
            }
            return !( localExtensions.some(
                localExtension => localExtension.local && this.uriIdentityService.extUri.isEqual(localExtension.local.location, extensionId)
            ));
        }));
        const installableRecommendations = await this.getInstallableRecommendations(allRecommendations, {
            ...options,
            source: "recommendations-all",
            sortBy: undefined
        }, token);
        const result = [];
        for (let i = 0; i < installableRecommendations.length && result.length < 8; i++) {
            const recommendation = allRecommendations[i];
            if (isString(recommendation)) {
                const extension = installableRecommendations.find(extension => areSameExtensions(extension.identifier, {
                    id: recommendation
                }));
                if (extension) {
                    result.push(extension);
                }
            } else {
                const extension = installableRecommendations.find(
                    extension => extension.resourceExtension && this.uriIdentityService.extUri.isEqual(extension.resourceExtension.location, recommendation)
                );
                if (extension) {
                    result.push(extension);
                }
            }
        }
        return ( new PagedModel(result));
    }
    async searchRecommendations(query, options, token) {
        const value = query.value.replace(/@recommended/g, "").trim().toLowerCase();
        const recommendations = distinct([
            ...(await this.getWorkspaceRecommendations()),
            ...(await this.getOtherRecommendations())
        ]);
        const installableRecommendations = (await this.getInstallableRecommendations(recommendations, {
            ...options,
            source: "recommendations",
            sortBy: undefined
        }, token)).filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1);
        return ( new PagedModel(this.sortExtensions(installableRecommendations, options)));
    }
    setModel(model, message, donotResetScrollTop) {
        if (this.list) {
            this.list.model = ( new DelayedPagedModel(model));
            this.updateBody(message);
            if (!donotResetScrollTop) {
                this.list.scrollTop = 0;
            }
        }
        if (this.badge) {
            this.badge.setCount(this.count());
        }
    }
    updateModel(model) {
        if (this.list) {
            this.list.model = ( new DelayedPagedModel(model));
            this.updateBody();
        }
        if (this.badge) {
            this.badge.setCount(this.count());
        }
    }
    updateBody(message) {
        if (this.bodyTemplate) {
            const count = this.count();
            this.bodyTemplate.extensionsList.classList.toggle("hidden", count === 0);
            this.bodyTemplate.messageContainer.classList.toggle("hidden", !message && count > 0);
            if (this.isBodyVisible()) {
                if (message) {
                    this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(message.severity);
                    this.bodyTemplate.messageBox.textContent = message.text;
                } else if (this.count() === 0) {
                    this.bodyTemplate.messageSeverityIcon.className = "";
                    this.bodyTemplate.messageBox.textContent = ( localize(9304, "No extensions found."));
                }
                if (this.bodyTemplate.messageBox.textContent) {
                    alert(this.bodyTemplate.messageBox.textContent);
                }
            }
        }
        this.updateSize();
    }
    getMessage(error) {
        if (this.isOfflineError(error)) {
            return {
                text: ( localize(
                    9305,
                    "Unable to search the Marketplace when offline, please check your network connection."
                )),
                severity: Severity$1.Warning
            };
        } else {
            return {
                text: ( localize(9306, "Error while fetching extensions. {0}", getErrorMessage(error))),
                severity: Severity$1.Error
            };
        }
    }
    isOfflineError(error) {
        if (error instanceof ExtensionGalleryError) {
            return error.code === ExtensionGalleryErrorCode.Offline;
        }
        return isOfflineError(error);
    }
    updateSize() {
        if (this.options.flexibleHeight) {
            this.maximumBodySize = this.list?.model.length ? Number.POSITIVE_INFINITY : 0;
            this.storageService.store(
                `${this.id}.size`,
                this.list?.model.length || 0,
                StorageScope.PROFILE,
                StorageTarget.MACHINE
            );
        }
    }
    dispose() {
        super.dispose();
        if (this.queryRequest) {
            this.queryRequest.request.cancel();
            this.queryRequest = null;
        }
        if (this.queryResult) {
            this.queryResult.disposables.dispose();
            this.queryResult = undefined;
        }
        this.list = null;
    }
    static isLocalExtensionsQuery(query, sortBy) {
        return this.isInstalledExtensionsQuery(query) || this.isSearchInstalledExtensionsQuery(query) || this.isOutdatedExtensionsQuery(query) || this.isEnabledExtensionsQuery(query) || this.isDisabledExtensionsQuery(query) || this.isBuiltInExtensionsQuery(query) || this.isSearchBuiltInExtensionsQuery(query) || this.isBuiltInGroupExtensionsQuery(query) || this.isSearchDeprecatedExtensionsQuery(query) || this.isSearchWorkspaceUnsupportedExtensionsQuery(query) || this.isSearchRecentlyUpdatedQuery(query) || this.isRestartRequiredQuery(query) || this.isSearchExtensionUpdatesQuery(query) || this.isSortInstalledExtensionsQuery(query, sortBy) || this.isFeatureExtensionsQuery(query);
    }
    static isSearchBuiltInExtensionsQuery(query) {
        return /@builtin\s.+|.+\s@builtin/i.test(query);
    }
    static isBuiltInExtensionsQuery(query) {
        return /^@builtin$/i.test(query.trim());
    }
    static isBuiltInGroupExtensionsQuery(query) {
        return /^@builtin:.+$/i.test(query.trim());
    }
    static isSearchWorkspaceUnsupportedExtensionsQuery(query) {
        return /^\s*@workspaceUnsupported(:(untrusted|virtual)(Partial)?)?(\s|$)/i.test(query);
    }
    static isInstalledExtensionsQuery(query) {
        return /@installed$/i.test(query) && !/@mcp/i.test(query) && !/@agentPlugins/i.test(query);
    }
    static isSearchInstalledExtensionsQuery(query) {
        return (/@installed\s./i.test(query) && !/@mcp/i.test(query) && !/@agentPlugins/i.test(query)) || this.isFeatureExtensionsQuery(query);
    }
    static isOutdatedExtensionsQuery(query) {
        return /@outdated/i.test(query);
    }
    static isEnabledExtensionsQuery(query) {
        return /@enabled/i.test(query) && !/@builtin/i.test(query);
    }
    static isDisabledExtensionsQuery(query) {
        return /@disabled/i.test(query) && !/@builtin/i.test(query);
    }
    static isSearchDeprecatedExtensionsQuery(query) {
        return /@deprecated\s?.*/i.test(query);
    }
    static isRecommendedExtensionsQuery(query) {
        return /^@recommended$/i.test(query.trim());
    }
    static isSearchRecommendedExtensionsQuery(query) {
        return /@recommended\s.+/i.test(query);
    }
    static isWorkspaceRecommendedExtensionsQuery(query) {
        return /@recommended:workspace/i.test(query);
    }
    static isExeRecommendedExtensionsQuery(query) {
        return /@exe:.+/i.test(query);
    }
    static isRemoteRecommendedExtensionsQuery(query) {
        return /@recommended:remotes/i.test(query);
    }
    static isKeymapsRecommendedExtensionsQuery(query) {
        return /@recommended:keymaps/i.test(query);
    }
    static isLanguageRecommendedExtensionsQuery(query) {
        return /@recommended:languages/i.test(query);
    }
    static isSortInstalledExtensionsQuery(query, sortBy) {
        return (sortBy !== undefined && sortBy !== "" && query === "") || (!sortBy && /^@sort:\S*$/i.test(query));
    }
    static isSearchPopularQuery(query) {
        return /@popular/i.test(query);
    }
    static isSearchRecentlyPublishedQuery(query) {
        return /@recentlyPublished/i.test(query);
    }
    static isSearchRecentlyUpdatedQuery(query) {
        return /@recentlyUpdated/i.test(query);
    }
    static isRestartRequiredQuery(query) {
        return /@restartrequired/i.test(query);
    }
    static isSearchExtensionUpdatesQuery(query) {
        return /@updates/i.test(query);
    }
    static isSortUpdateDateQuery(query) {
        return /@sort:updateDate/i.test(query);
    }
    static isFeatureExtensionsQuery(query) {
        return /@contribute:/i.test(query);
    }
    focus() {
        super.focus();
        if (!this.list) {
            return;
        }
        if (!(this.list.getFocus().length || this.list.getSelection().length)) {
            this.list.focusNext();
        }
        this.list.domFocus();
    }
};
ExtensionsListView = ExtensionsListView_1 = ( __decorate([( __param(2, INotificationService)), ( __param(3, IKeybindingService)), ( __param(4, IContextMenuService)), ( __param(5, IInstantiationService)), ( __param(6, IThemeService)), ( __param(7, IExtensionService)), ( __param(8, IExtensionsWorkbenchService)), ( __param(9, IExtensionRecommendationsService)), ( __param(10, ITelemetryService)), ( __param(11, IHoverService)), ( __param(12, IConfigurationService)), ( __param(13, IWorkspaceContextService)), ( __param(14, IExtensionManagementServerService)), ( __param(15, IExtensionManifestPropertiesService)), ( __param(16, IWorkbenchExtensionManagementService)), ( __param(17, IWorkspaceContextService)), ( __param(18, IProductService)), ( __param(19, IContextKeyService)), ( __param(20, IViewDescriptorService)), ( __param(21, IOpenerService)), ( __param(22, IStorageService)), ( __param(23, IWorkspaceTrustManagementService)), ( __param(24, IWorkbenchExtensionEnablementService)), ( __param(25, IExtensionFeaturesManagementService)), ( __param(26, IUriIdentityService)), ( __param(27, ILogService))], ExtensionsListView));
class DefaultPopularExtensionsView extends ExtensionsListView {
    async show() {
        const query = this.extensionManagementServerService.webExtensionManagementServer && !this.extensionManagementServerService.localExtensionManagementServer && !this.extensionManagementServerService.remoteExtensionManagementServer ? "@web" : "";
        return super.show(query);
    }
}
class ServerInstalledExtensionsView extends ExtensionsListView {
    async show(query) {
        query = query ? query : "@installed";
        if (!ExtensionsListView.isLocalExtensionsQuery(query) || ExtensionsListView.isSortInstalledExtensionsQuery(query)) {
            query = query += " @installed";
        }
        return super.show(query.trim());
    }
}
class EnabledExtensionsView extends ExtensionsListView {
    async show(query) {
        query = query || "@enabled";
        return ExtensionsListView.isEnabledExtensionsQuery(query) ? super.show(query) : ExtensionsListView.isSortInstalledExtensionsQuery(query) ? super.show("@enabled " + query) : this.showEmptyModel();
    }
}
class DisabledExtensionsView extends ExtensionsListView {
    async show(query) {
        query = query || "@disabled";
        return ExtensionsListView.isDisabledExtensionsQuery(query) ? super.show(query) : ExtensionsListView.isSortInstalledExtensionsQuery(query) ? super.show("@disabled " + query) : this.showEmptyModel();
    }
}
class OutdatedExtensionsView extends ExtensionsListView {
    async show(query) {
        query = query ? query : "@outdated";
        if (ExtensionsListView.isSearchExtensionUpdatesQuery(query)) {
            query = query.replace("@updates", "@outdated");
        }
        return super.show(query.trim());
    }
    updateSize() {
        super.updateSize();
        this.setExpanded(this.count() > 0);
    }
}
class RecentlyUpdatedExtensionsView extends ExtensionsListView {
    async show(query) {
        query = query ? query : "@recentlyUpdated";
        if (ExtensionsListView.isSearchExtensionUpdatesQuery(query)) {
            query = query.replace("@updates", "@recentlyUpdated");
        }
        return super.show(query.trim());
    }
}
let StaticQueryExtensionsView = class StaticQueryExtensionsView extends ExtensionsListView {
    constructor(
        options,
        viewletViewOptions,
        notificationService,
        keybindingService,
        contextMenuService,
        instantiationService,
        themeService,
        extensionService,
        extensionsWorkbenchService,
        extensionRecommendationsService,
        telemetryService,
        hoverService,
        configurationService,
        contextService,
        extensionManagementServerService,
        extensionManifestPropertiesService,
        extensionManagementService,
        workspaceService,
        productService,
        contextKeyService,
        viewDescriptorService,
        openerService,
        storageService,
        workspaceTrustManagementService,
        extensionEnablementService,
        extensionFeaturesManagementService,
        uriIdentityService,
        logService
    ) {
        super(
            options,
            viewletViewOptions,
            notificationService,
            keybindingService,
            contextMenuService,
            instantiationService,
            themeService,
            extensionService,
            extensionsWorkbenchService,
            extensionRecommendationsService,
            telemetryService,
            hoverService,
            configurationService,
            contextService,
            extensionManagementServerService,
            extensionManifestPropertiesService,
            extensionManagementService,
            workspaceService,
            productService,
            contextKeyService,
            viewDescriptorService,
            openerService,
            storageService,
            workspaceTrustManagementService,
            extensionEnablementService,
            extensionFeaturesManagementService,
            uriIdentityService,
            logService
        );
        this.options = options;
    }
    show() {
        return super.show(this.options.query);
    }
};
StaticQueryExtensionsView = ( __decorate([( __param(2, INotificationService)), ( __param(3, IKeybindingService)), ( __param(4, IContextMenuService)), ( __param(5, IInstantiationService)), ( __param(6, IThemeService)), ( __param(7, IExtensionService)), ( __param(8, IExtensionsWorkbenchService)), ( __param(9, IExtensionRecommendationsService)), ( __param(10, ITelemetryService)), ( __param(11, IHoverService)), ( __param(12, IConfigurationService)), ( __param(13, IWorkspaceContextService)), ( __param(14, IExtensionManagementServerService)), ( __param(15, IExtensionManifestPropertiesService)), ( __param(16, IWorkbenchExtensionManagementService)), ( __param(17, IWorkspaceContextService)), ( __param(18, IProductService)), ( __param(19, IContextKeyService)), ( __param(20, IViewDescriptorService)), ( __param(21, IOpenerService)), ( __param(22, IStorageService)), ( __param(23, IWorkspaceTrustManagementService)), ( __param(24, IWorkbenchExtensionEnablementService)), ( __param(25, IExtensionFeaturesManagementService)), ( __param(26, IUriIdentityService)), ( __param(27, ILogService))], StaticQueryExtensionsView));
function toSpecificWorkspaceUnsupportedQuery(query, qualifier) {
    if (!query) {
        return "@workspaceUnsupported:" + qualifier;
    }
    const match = query.match(( new RegExp(`@workspaceUnsupported(:${qualifier})?(\\s|$)`, "i")));
    if (match) {
        if (!match[1]) {
            return query.replace(/@workspaceUnsupported/gi, "@workspaceUnsupported:" + qualifier);
        }
        return query;
    }
    return undefined;
}
class UntrustedWorkspaceUnsupportedExtensionsView extends ExtensionsListView {
    async show(query) {
        const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, "untrusted");
        return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel();
    }
}
class UntrustedWorkspacePartiallySupportedExtensionsView extends ExtensionsListView {
    async show(query) {
        const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, "untrustedPartial");
        return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel();
    }
}
class VirtualWorkspaceUnsupportedExtensionsView extends ExtensionsListView {
    async show(query) {
        const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, "virtual");
        return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel();
    }
}
class VirtualWorkspacePartiallySupportedExtensionsView extends ExtensionsListView {
    async show(query) {
        const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, "virtualPartial");
        return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel();
    }
}
class DeprecatedExtensionsView extends ExtensionsListView {
    async show(query) {
        return ExtensionsListView.isSearchDeprecatedExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
    }
}
class SearchMarketplaceExtensionsView extends ExtensionsListView {
    constructor() {
        super(...arguments);
        this.reportSearchFinishedDelayer = this._register(( new ThrottledDelayer(2000)));
        this.searchWaitPromise = Promise.resolve();
    }
    async show(query) {
        const queryPromise = super.show(query);
        this.reportSearchFinishedDelayer.trigger(() => this.reportSearchFinished());
        this.searchWaitPromise = queryPromise.then(null, null);
        return queryPromise;
    }
    async reportSearchFinished() {
        await this.searchWaitPromise;
        this.telemetryService.publicLog2("extensionsView:MarketplaceSearchFinished");
    }
}
class DefaultRecommendedExtensionsView extends ExtensionsListView {
    constructor() {
        super(...arguments);
        this.recommendedExtensionsQuery = "@recommended:all";
    }
    renderBody(container) {
        super.renderBody(container);
        this._register(this.extensionRecommendationsService.onDidChangeRecommendations(() => {
            this.show("");
        }));
    }
    async show(query) {
        if (query && query.trim() !== this.recommendedExtensionsQuery) {
            return this.showEmptyModel();
        }
        const model = await super.show(this.recommendedExtensionsQuery);
        if (!( this.extensionsWorkbenchService.local.some(e => !e.isBuiltin))) {
            this.setExpanded(model.length > 0);
        }
        return model;
    }
}
class RecommendedExtensionsView extends ExtensionsListView {
    constructor() {
        super(...arguments);
        this.recommendedExtensionsQuery = "@recommended";
    }
    renderBody(container) {
        super.renderBody(container);
        this._register(this.extensionRecommendationsService.onDidChangeRecommendations(() => {
            this.show("");
        }));
    }
    async show(query) {
        return (query && query.trim() !== this.recommendedExtensionsQuery) ? this.showEmptyModel() : super.show(this.recommendedExtensionsQuery);
    }
}
class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
    constructor() {
        super(...arguments);
        this.recommendedExtensionsQuery = "@recommended:workspace";
    }
    renderBody(container) {
        super.renderBody(container);
        this._register(
            this.extensionRecommendationsService.onDidChangeRecommendations(() => this.show(this.recommendedExtensionsQuery))
        );
        this._register(
            this.contextService.onDidChangeWorkbenchState(() => this.show(this.recommendedExtensionsQuery))
        );
    }
    async show(query) {
        const shouldShowEmptyView = query && query.trim() !== "@recommended" && query.trim() !== "@recommended:workspace";
        const model = await (shouldShowEmptyView ? this.showEmptyModel() : super.show(this.recommendedExtensionsQuery));
        this.setExpanded(model.length > 0);
        return model;
    }
    async getInstallableWorkspaceRecommendations() {
        const installed = (await this.extensionsWorkbenchService.queryLocal()).filter(l => l.enablementState !== EnablementState.DisabledByExtensionKind);
        const recommendations = (await this.getWorkspaceRecommendations()).filter(
            recommendation => installed.every(local => isString(recommendation) ? !areSameExtensions({
                id: recommendation
            }, local.identifier) : !this.uriIdentityService.extUri.isEqual(recommendation, local.local?.location))
        );
        return this.getInstallableRecommendations(recommendations, {
            source: "install-all-workspace-recommendations"
        }, CancellationToken.None);
    }
    async installWorkspaceRecommendations() {
        const installableRecommendations = await this.getInstallableWorkspaceRecommendations();
        if (installableRecommendations.length) {
            const galleryExtensions = [];
            const resourceExtensions = [];
            for (const recommendation of installableRecommendations) {
                if (recommendation.gallery) {
                    galleryExtensions.push({
                        extension: recommendation.gallery,
                        options: {}
                    });
                } else {
                    resourceExtensions.push(recommendation);
                }
            }
            await Promise.all([
                this.extensionManagementService.installGalleryExtensions(galleryExtensions),
                ...( resourceExtensions.map(extension => this.extensionsWorkbenchService.install(extension)))
            ]);
        } else {
            this.notificationService.notify({
                severity: Severity$1.Info,
                message: ( localize(9307, "There are no extensions to install."))
            });
        }
    }
}
class PreferredExtensionsPagedModel {
    get onDidIncrementLength() {
        return Event.None;
    }
    constructor(preferredExtensions, pager) {
        this.preferredExtensions = preferredExtensions;
        this.pager = pager;
        this.resolved = ( new Map());
        this.preferredGalleryExtensions = ( new Set());
        this.resolvedGalleryExtensionsFromQuery = [];
        for (let i = 0; i < this.preferredExtensions.length; i++) {
            this.resolved.set(i, this.preferredExtensions[i]);
        }
        for (const e of preferredExtensions) {
            if (e.identifier.uuid) {
                this.preferredGalleryExtensions.add(e.identifier.uuid);
            }
        }
        this.length = (preferredExtensions.length - this.preferredGalleryExtensions.size) + this.pager.total;
        const totalPages = Math.ceil(this.pager.total / this.pager.pageSize);
        this.populateResolvedExtensions(0, this.pager.firstPage);
        this.pages = ( range(totalPages - 1).map(() => ({
            promise: null,
            cts: null,
            promiseIndexes: ( new Set())
        })));
    }
    isResolved(index) {
        return ( this.resolved.has(index));
    }
    get(index) {
        return this.resolved.get(index);
    }
    async resolve(index, cancellationToken) {
        if (cancellationToken.isCancellationRequested) {
            throw ( new CancellationError());
        }
        if (this.isResolved(index)) {
            return this.get(index);
        }
        const indexInPagedModel = index - this.preferredExtensions.length + this.resolvedGalleryExtensionsFromQuery.length;
        const pageIndex = Math.floor(indexInPagedModel / this.pager.pageSize);
        const page = this.pages[pageIndex];
        if (!page.promise) {
            page.cts = ( new CancellationTokenSource());
            page.promise = this.pager.getPage(pageIndex, page.cts.token).then(extensions => this.populateResolvedExtensions(pageIndex, extensions)).catch(e => {
                page.promise = null;
                throw e;
            }).finally(() => page.cts = null);
        }
        const listener = cancellationToken.onCancellationRequested(() => {
            if (!page.cts) {
                return;
            }
            page.promiseIndexes.delete(index);
            if (page.promiseIndexes.size === 0) {
                page.cts.cancel();
            }
        });
        page.promiseIndexes.add(index);
        try {
            await page.promise;
        } finally {
            listener.dispose();
        }
        return this.get(index);
    }
    populateResolvedExtensions(pageIndex, extensions) {
        let adjustIndexOfNextPagesBy = 0;
        const pageStartIndex = pageIndex * this.pager.pageSize;
        for (let i = 0; i < extensions.length; i++) {
            const e = extensions[i];
            if (e.gallery?.identifier.uuid && ( this.preferredGalleryExtensions.has(e.gallery.identifier.uuid))) {
                this.resolvedGalleryExtensionsFromQuery.push(e);
                adjustIndexOfNextPagesBy++;
            } else {
                this.resolved.set(
                    this.preferredExtensions.length - this.resolvedGalleryExtensionsFromQuery.length + pageStartIndex + i,
                    e
                );
            }
        }
        if (pageIndex !== 0 && adjustIndexOfNextPagesBy) {
            const nextPageStartIndex = (pageIndex + 1) * this.pager.pageSize;
            const indices = [...( this.resolved.keys())].sort();
            for (const index of indices) {
                if (index >= nextPageStartIndex) {
                    const e = this.resolved.get(index);
                    if (e) {
                        this.resolved.delete(index);
                        this.resolved.set(index - adjustIndexOfNextPagesBy, e);
                    }
                }
            }
        }
    }
}

export { AbstractExtensionsListView, DefaultPopularExtensionsView, DefaultRecommendedExtensionsView, DeprecatedExtensionsView, DisabledExtensionsView, EnabledExtensionsView, ExtensionsListView, NONE_CATEGORY, OutdatedExtensionsView, PreferredExtensionsPagedModel, RecentlyUpdatedExtensionsView, RecommendedExtensionsView, SearchMarketplaceExtensionsView, ServerInstalledExtensionsView, StaticQueryExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, WorkspaceRecommendedExtensionsView };
