2016-09-13 15:41:52 +05:30
|
|
|
// @flow
|
|
|
|
|
|
|
|
|
|
import type {Component} from 'react';
|
2016-06-01 16:54:21 +05:30
|
|
|
import CommandProvider from './CommandProvider';
|
2016-06-12 17:02:46 +05:30
|
|
|
import DuckDuckGoProvider from './DuckDuckGoProvider';
|
|
|
|
|
import RoomProvider from './RoomProvider';
|
|
|
|
|
import UserProvider from './UserProvider';
|
2016-06-17 04:58:09 +05:30
|
|
|
import EmojiProvider from './EmojiProvider';
|
2016-09-13 15:41:52 +05:30
|
|
|
import Q from 'q';
|
|
|
|
|
|
|
|
|
|
export type SelectionRange = {
|
|
|
|
|
start: number,
|
|
|
|
|
end: number
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type Completion = {
|
|
|
|
|
completion: string,
|
|
|
|
|
component: ?Component,
|
|
|
|
|
range: SelectionRange,
|
|
|
|
|
command: ?string,
|
|
|
|
|
};
|
2016-06-01 16:54:21 +05:30
|
|
|
|
2016-06-12 17:02:46 +05:30
|
|
|
const PROVIDERS = [
|
2016-06-20 13:52:55 +05:30
|
|
|
UserProvider,
|
2016-06-12 17:02:46 +05:30
|
|
|
RoomProvider,
|
2016-07-03 22:15:13 +05:30
|
|
|
EmojiProvider,
|
2016-09-13 15:41:52 +05:30
|
|
|
CommandProvider,
|
|
|
|
|
DuckDuckGoProvider,
|
2016-06-20 13:52:55 +05:30
|
|
|
].map(completer => completer.getInstance());
|
2016-06-01 16:54:21 +05:30
|
|
|
|
2016-09-13 15:41:52 +05:30
|
|
|
// Providers will get rejected if they take longer than this.
|
|
|
|
|
const PROVIDER_COMPLETION_TIMEOUT = 3000;
|
|
|
|
|
|
|
|
|
|
export async function getCompletions(query: string, selection: SelectionRange, force: boolean = false): Array<Completion> {
|
|
|
|
|
/* Note: That this waits for all providers to return is *intentional*
|
|
|
|
|
otherwise, we run into a condition where new completions are displayed
|
|
|
|
|
while the user is interacting with the list, which makes it difficult
|
|
|
|
|
to predict whether an action will actually do what is intended
|
|
|
|
|
|
|
|
|
|
It ends up containing a list of Q promise states, which are objects with
|
|
|
|
|
state (== "fulfilled" || "rejected") and value. */
|
|
|
|
|
const completionsList = await Q.allSettled(
|
|
|
|
|
PROVIDERS.map(provider => {
|
|
|
|
|
return Q(provider.getCompletions(query, selection, force))
|
|
|
|
|
.timeout(PROVIDER_COMPLETION_TIMEOUT);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return completionsList
|
|
|
|
|
.filter(completion => completion.state === "fulfilled")
|
|
|
|
|
.map((completionsState, i) => {
|
|
|
|
|
return {
|
|
|
|
|
completions: completionsState.value,
|
|
|
|
|
provider: PROVIDERS[i],
|
|
|
|
|
|
|
|
|
|
/* the currently matched "command" the completer tried to complete
|
|
|
|
|
* we pass this through so that Autocomplete can figure out when to
|
|
|
|
|
* re-show itself once hidden.
|
|
|
|
|
*/
|
|
|
|
|
command: PROVIDERS[i].getCurrentCommand(query, selection, force),
|
|
|
|
|
};
|
|
|
|
|
});
|
2016-06-01 16:54:21 +05:30
|
|
|
}
|