Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a prefix-based quick open handler should be initialized on each open #2744

Merged
merged 1 commit into from
Aug 31, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 51 additions & 77 deletions packages/core/src/browser/quick-open/prefix-quick-open-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable, inject, postConstruct } from 'inversify';
import { injectable, inject } from 'inversify';
import { QuickOpenModel, QuickOpenItem, QuickOpenMode } from './quick-open-model';
import { QuickOpenService, QuickOpenOptions } from './quick-open-service';
import { Disposable, DisposableCollection } from '../../common/disposable';
Expand Down Expand Up @@ -129,81 +129,16 @@ export class QuickOpenHandlerRegistry implements Disposable {
}
}

/**
* The quick open model just delegates all the calls to another model depending on the used prefix.
*/
class PrefixModel implements QuickOpenModel {

/**
* Stores the current handler for the quick open widget opened in a prefix-aware mode.
* Allows to detect that another model is called.
*/
protected currentHandler: QuickOpenHandler;

constructor(
protected readonly handlers: QuickOpenHandlerRegistry,
protected readonly openService: PrefixQuickOpenService
) { }

onType(lookFor: string, acceptor: (items: QuickOpenItem[]) => void): void {
const handler = this.handlers.getHandlerOrDefault(lookFor);
if (handler === undefined) {
const items: QuickOpenItem[] = [];
items.push(new QuickOpenItem({
label: lookFor.length === 0 ? 'No default handler is registered' : `No handlers matches the prefix ${lookFor} and no default handler is registered.`
}));
acceptor(items);
} else if (handler !== this.currentHandler) {
this.onHandlerChanged(handler, lookFor);
} else {
const handlerModel = handler.getModel();
const searchValue = this.handlers.isDefaultHandler(handler) ? lookFor : lookFor.substr(handler.prefix.length);
handlerModel.onType(searchValue, items => acceptor(items));
}
}

/**
* Handles changing the currently used handler as a result of user's typing.
* @param handler quick open handler that should be used
* @param prefix value that is currently typed in the quick open widget
*/
protected async onHandlerChanged(handler: QuickOpenHandler, prefix: string): Promise<void> {
// need to notify the previous handler's model about closing the quick open widget
if (this.currentHandler) {
const closingHandler = this.currentHandler.getOptions().onClose;
if (closingHandler) {
closingHandler(true);
}
}
this.currentHandler = handler;
if (handler.init) {
await handler.init();
}
// a prefix has been changed, so the quick open widget needs to be reopened with the new options
this.openService.open(prefix);
}
}

/** Prefix-based quick open service. */
@injectable()
export class PrefixQuickOpenService {

/**
* The internal model which is used when the quick open widget is opened in handling prefix mode.
*/
protected model: QuickOpenModel;

@inject(QuickOpenHandlerRegistry)
protected readonly handlers: QuickOpenHandlerRegistry;

@inject(QuickOpenService)
protected readonly quickOpenService: QuickOpenService;

@postConstruct()
init() {
this.model = new PrefixModel(this.handlers, this);
}

/**
* Opens a quick open widget with the model that handles the known prefixes.
* @param prefix string that may contain a prefix of some of the known quick open handlers.
Expand All @@ -212,26 +147,65 @@ export class PrefixQuickOpenService {
*/
open(prefix: string): void {
const handler = this.handlers.getHandlerOrDefault(prefix);
if (handler === undefined) {
this.quickOpenService.open(this.model);
this.setCurrentHandler(prefix, handler);
}

protected toDisposeCurrent = new DisposableCollection();
protected currentHandler: QuickOpenHandler | undefined;

protected async setCurrentHandler(prefix: string, handler: QuickOpenHandler | undefined): Promise<void> {
this.toDisposeCurrent.dispose();
this.currentHandler = handler;
this.toDisposeCurrent.push(Disposable.create(() => {
const closingHandler = handler && handler.getOptions().onClose;
if (closingHandler) {
closingHandler(true);
}
}));
if (!handler) {
this.doOpen();
return;
}

if (handler.init) {
await handler.init();
}
let optionsPrefix = prefix;
// cut the prefix for a default handler
if (this.handlers.isDefaultHandler(handler) && prefix.startsWith(handler.prefix)) {
optionsPrefix = prefix.substr(handler.prefix.length);
}
const skipPrefix = this.handlers.isDefaultHandler(handler) ? 0 : handler.prefix.length;
const handlerOptions = QuickOpenOptions.resolve(handler.getOptions());
const placeholder = handlerOptions.placeholder || "Type '?' to get help on the actions you can take from here";
const options = QuickOpenOptions.resolve({
const handlerOptions = handler.getOptions();
this.doOpen({
prefix: optionsPrefix,
placeholder,
skipPrefix
}, handlerOptions);
this.quickOpenService.open(this.model, options);
placeholder: "Type '?' to get help on the actions you can take from here",
skipPrefix,
...handlerOptions
});
}

protected doOpen(options?: QuickOpenOptions): void {
this.quickOpenService.open({
onType: (lookFor, acceptor) => this.onType(lookFor, acceptor)
}, options);
}

protected onType(lookFor: string, acceptor: (items: QuickOpenItem[]) => void): void {
const handler = this.handlers.getHandlerOrDefault(lookFor);
if (handler === undefined) {
const items: QuickOpenItem[] = [];
items.push(new QuickOpenItem({
label: lookFor.length === 0 ? 'No default handler is registered' : `No handlers matches the prefix ${lookFor} and no default handler is registered.`
}));
acceptor(items);
} else if (handler !== this.currentHandler) {
this.setCurrentHandler(lookFor, handler);
} else {
const handlerModel = handler.getModel();
const searchValue = this.handlers.isDefaultHandler(handler) ? lookFor : lookFor.substr(handler.prefix.length);
handlerModel.onType(searchValue, items => acceptor(items));
}
}

}

@injectable()
Expand Down