/********************************************************************************
 * Copyright (C) 2017 TypeFox and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License v. 2.0 are satisfied: GNU General Public License, version 2
 * with the GNU Classpath Exception which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 ********************************************************************************/ import { named , injectable , inject } from 'inversify' ; import URI from '../common/uri' ; import { ContributionProvider , Prioritizeable , MaybePromise , Emitter , Event , Disposable } from '../common' ; export interface OpenerOptions { } export const OpenHandler = Symbol ( 'OpenHandler' ) ; /**
 * `OpenHandler` should be implemented to provide a new opener.
 */ export interface OpenHandler { /**
     * A unique id of this handler.
     */ readonly id : string ; /**
     * A human-readable name of this handler.
     */ readonly label ? : string ; /**
     * A css icon class of this handler.
     */ readonly iconClass ? : string ; /**
     * Test whether this handler can open the given URI for given options.
     * Return a nonzero number if this handler can open; otherwise it cannot.
     * Never reject.
     *
     * A returned value indicating a priority of this handler.
     */ canHandle ( uri , options ? ) : MaybePromise < number > ; /**
     * Open a widget for the given URI and options.
     * Resolve to an opened widget or undefined, e.g. if a page is opened.
     * Never reject if `canHandle` return a positive number; otherwise should reject.
     */ open ( uri , options ? ) : MaybePromise < object | undefined > ; } export const OpenerService = Symbol ( 'OpenerService' ) ; /**
 * `OpenerService` provide an access to existing openers.
 */ export interface OpenerService { /**
     * Return all registered openers.
     * Never reject.
     */ getOpeners ( ) : Promise < OpenHandler [ ] > ; /**
     * Return all openers able to open the given URI for given options
     * ordered according their priority.
     * Never reject.
     */ getOpeners ( uri , options ? ) : Promise < OpenHandler [ ] > ; /**
     * Return an opener with the higher priority for the given URI.
     * Reject if such does not exist.
     */ getOpener ( uri , options ? ) : Promise < OpenHandler > ; /**
     * Add open handler i.e. for custom editors
     */ addHandler ? ( openHandler ) : Disposable ; /**
     * Event that fires when a new opener is added or removed.
     */ onDidChangeOpeners ? : Event < void > ; } export async function open ( openerService , uri , options ? ) { const opener = await openerService . getOpener ( uri , options ) ; return opener . open ( uri , options ) ; } @ injectable ( ) export class DefaultOpenerService implements OpenerService { protected readonly customEditorOpenHandlers : OpenHandler [ ] = [ ] ; protected readonly onDidChangeOpenersEmitter = new Emitter < void > ( ) ; readonly onDidChangeOpeners = this . onDidChangeOpenersEmitter . event ; constructor ( @ inject ( ContributionProvider ) @ named ( OpenHandler ) protected readonly handlersProvider ) { } addHandler ( openHandler ) { this . customEditorOpenHandlers . push ( openHandler ) ; this . onDidChangeOpenersEmitter . fire ( ) ; return Disposable . create ( ( ) => { this . customEditorOpenHandlers . splice ( this . customEditorOpenHandlers . indexOf ( openHandler ) , 1 ) ; this . onDidChangeOpenersEmitter . fire ( ) ; } ) ; } async getOpener ( uri , options ? ) { const handlers = await this . prioritize ( uri , options ) ; if ( handlers . length >= 1 ) { return handlers [ 0 ] ; } return Promise . reject ( new Error ( `There is no opener for ${ uri }.` ) ) ; } async getOpeners ( uri ? , options ? ) { return uri ? this . prioritize ( uri , options ) : this . getHandlers ( ) ; } protected async prioritize ( uri , options ? ) { const prioritized = await Prioritizeable . prioritizeAll ( this . getHandlers ( ) , async ( handler ) => { try { return await handler . canHandle ( uri , options ) ; } catch { return 0 ; } } ) ; return prioritized . map ( p => p . value ) ; } protected getHandlers ( ) { return [ ... this . handlersProvider . getContributions ( ) , ... this . customEditorOpenHandlers ] ; } }