aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2020-03-26 22:17:00 +0900
committerShin'ya Ueoka <ueokande@i-beam.org>2020-03-26 22:17:00 +0900
commitb2a37b8fc3e273dd71e1e3558c58be8002aa3789 (patch)
tree9e6f0d354beca92e975dc97462b3860833112f81
parent6829e24c62c0291336502b3390905b57b81abd21 (diff)
Query completions on open command by a completion source
-rw-r--r--src/background/completion/CompletionUseCase.ts21
-rw-r--r--src/background/controllers/CompletionController.ts31
-rw-r--r--src/background/infrastructures/ContentMessageListener.ts10
-rw-r--r--src/console/actions/console.ts61
-rw-r--r--src/console/actions/index.ts2
-rw-r--r--src/console/clients/CompletionClient.ts54
-rw-r--r--src/console/components/Console.tsx12
-rw-r--r--src/console/index.tsx4
-rw-r--r--src/console/reducers/index.ts4
-rw-r--r--src/shared/CompletionType.ts7
-rw-r--r--src/shared/messages.ts46
11 files changed, 244 insertions, 8 deletions
diff --git a/src/background/completion/CompletionUseCase.ts b/src/background/completion/CompletionUseCase.ts
index 898efd4..fd3c279 100644
--- a/src/background/completion/CompletionUseCase.ts
+++ b/src/background/completion/CompletionUseCase.ts
@@ -2,6 +2,7 @@ import { inject, injectable } from "tsyringe";
import HistoryRepository from "./HistoryRepository";
import BookmarkRepository from "./BookmarkRepository";
import CachedSettingRepository from "../repositories/CachedSettingRepository";
+import CompletionType from "../../shared/CompletionType";
export type BookmarkItem = {
title: string
@@ -23,6 +24,26 @@ export default class CompletionUseCase {
) {
}
+ async getCompletionTypes(): Promise<CompletionType[]> {
+ const settings = await this.cachedSettingRepository.get();
+ const types: CompletionType[] = [];
+ for (const c of settings.properties.complete) {
+ switch (c) {
+ case 's':
+ types.push(CompletionType.SearchEngines);
+ break;
+ case 'h':
+ types.push(CompletionType.History);
+ break;
+ case 'b':
+ types.push(CompletionType.Bookmarks);
+ break;
+ }
+ // ignore invalid characters in the complete property
+ }
+ return types;
+ }
+
async requestSearchEngines(query: string): Promise<string[]> {
const settings = await this.cachedSettingRepository.get();
return Object.keys(settings.search.engines)
diff --git a/src/background/controllers/CompletionController.ts b/src/background/controllers/CompletionController.ts
new file mode 100644
index 0000000..313f38b
--- /dev/null
+++ b/src/background/controllers/CompletionController.ts
@@ -0,0 +1,31 @@
+import {
+ ConsoleGetCompletionTypesResponse,
+ ConsoleRequestBookmarksResponse, ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse
+} from "../../shared/messages";
+import { injectable } from "tsyringe";
+import CompletionUseCase from "../completion/CompletionUseCase";
+
+@injectable()
+export default class CompletionController {
+ constructor(
+ private completionUseCase: CompletionUseCase,
+ ) {
+ }
+
+ async getCompletionTypes(): Promise<ConsoleGetCompletionTypesResponse> {
+ return this.completionUseCase.getCompletionTypes();
+ }
+
+ async requestSearchEngines(query: string): Promise<ConsoleRequestSearchEnginesResponse> {
+ const items = await this.completionUseCase.requestSearchEngines(query);
+ return items.map(name => ({ title: name }));
+ }
+
+ async requestBookmarks(query: string): Promise<ConsoleRequestBookmarksResponse> {
+ return this.completionUseCase.requestBookmarks(query);
+ }
+
+ async requestHistory(query: string): Promise<ConsoleRequestHistoryResponse> {
+ return this.completionUseCase.requestHistory(query);
+ }
+} \ No newline at end of file
diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts
index d063810..62cd49f 100644
--- a/src/background/infrastructures/ContentMessageListener.ts
+++ b/src/background/infrastructures/ContentMessageListener.ts
@@ -9,6 +9,7 @@ import AddonEnabledController from '../controllers/AddonEnabledController';
import LinkController from '../controllers/LinkController';
import OperationController from '../controllers/OperationController';
import MarkController from '../controllers/MarkController';
+import CompletionController from "../controllers/CompletionController";
@injectable()
export default class ContentMessageListener {
@@ -17,6 +18,7 @@ export default class ContentMessageListener {
constructor(
private settingController: SettingController,
private commandController: CommandController,
+ private completionController: CompletionController,
private findController: FindController,
private addonEnabledController: AddonEnabledController,
private linkController: LinkController,
@@ -63,6 +65,14 @@ export default class ContentMessageListener {
switch (message.type) {
case messages.CONSOLE_QUERY_COMPLETIONS:
return this.onConsoleQueryCompletions(message.text);
+ case messages.CONSOLE_GET_COMPLETION_TYPES:
+ return this.completionController.getCompletionTypes();
+ case messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE:
+ return this.completionController.requestSearchEngines(message.query);
+ case messages.CONSOLE_REQUEST_BOOKMARKS:
+ return this.completionController.requestBookmarks(message.query);
+ case messages.CONSOLE_REQUEST_HISTORY:
+ return this.completionController.requestHistory(message.query);
case messages.CONSOLE_ENTER_COMMAND:
return this.onConsoleEnterCommand(message.text);
case messages.SETTINGS_QUERY:
diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts
index cef04fe..99e58f7 100644
--- a/src/console/actions/console.ts
+++ b/src/console/actions/console.ts
@@ -1,6 +1,11 @@
import * as messages from '../../shared/messages';
import * as actions from './index';
import { Command } from "../../shared/Command";
+import CompletionClient from "../clients/CompletionClient";
+import CompletionType from "../../shared/CompletionType";
+import Completions from "../Completions";
+
+const completionClient = new CompletionClient();
const commandDocs = {
[Command.Set]: 'Set a value of the property',
@@ -22,10 +27,12 @@ const hide = (): actions.ConsoleAction => {
};
};
-const showCommand = (text: string): actions.ConsoleAction => {
+const showCommand = async (text: string): Promise<actions.ConsoleAction> => {
+ const completionTypes = await completionClient.getCompletionTypes();
return {
type: actions.CONSOLE_SHOW_COMMAND,
- text: text
+ completionTypes,
+ text,
};
};
@@ -102,6 +109,51 @@ const getCommandCompletions = (text: string): actions.ConsoleAction => {
}
};
+const getOpenCompletions = async(types: CompletionType[], original: string, command: Command, query: string): Promise<actions.ConsoleAction> => {
+ const completions: Completions = [];
+ for (const type of types) {
+ switch (type) {
+ case CompletionType.SearchEngines:
+ completions.push({
+ name: 'Search Engines',
+ items: (await completionClient.requestSearchEngines(query))
+ .map(key => ({
+ caption: key.title,
+ content: command + ' ' + key.title,
+ }))
+ });
+ break;
+ case CompletionType.History:
+ completions.push({
+ name: 'History',
+ items: (await completionClient.requestHistory(query))
+ .map(item => ({
+ caption: item.title,
+ content: command + ' ' + item.url,
+ url: item.url
+ })),
+ });
+ break;
+ case CompletionType.Bookmarks:
+ completions.push({
+ name: 'Bookmarks',
+ items: (await completionClient.requestBookmarks(query))
+ .map(item => ({
+ caption: item.title,
+ content: command + ' ' + item.url,
+ url: item.url
+ }))
+ });
+ break;
+ }
+ }
+
+ return {
+ type: actions.CONSOLE_SET_COMPLETIONS,
+ completions,
+ completionSource: original,
+ };
+};
const getCompletions = async(text: string): Promise<actions.ConsoleAction> => {
const completions = await browser.runtime.sendMessage({
@@ -128,6 +180,7 @@ const completionPrev = (): actions.ConsoleAction => {
};
export {
- hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText,
- enterCommand, enterFind, getCompletions, getCommandCompletions, completionNext, completionPrev,
+ hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText, enterCommand, enterFind,
+ getCompletions, getCommandCompletions, getOpenCompletions,
+ completionNext, completionPrev,
};
diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts
index d36f8cd..8448e04 100644
--- a/src/console/actions/index.ts
+++ b/src/console/actions/index.ts
@@ -1,4 +1,5 @@
import Completions from "../Completions";
+import CompletionType from "../../shared/CompletionType";
export const CONSOLE_HIDE = 'console.hide';
export const CONSOLE_SHOW_COMMAND = 'console.show.command';
@@ -18,6 +19,7 @@ interface HideAction {
interface ShowCommand {
type: typeof CONSOLE_SHOW_COMMAND;
text: string;
+ completionTypes: CompletionType[];
}
interface ShowFindAction {
diff --git a/src/console/clients/CompletionClient.ts b/src/console/clients/CompletionClient.ts
new file mode 100644
index 0000000..d5f9b01
--- /dev/null
+++ b/src/console/clients/CompletionClient.ts
@@ -0,0 +1,54 @@
+import * as messages from "../../shared/messages";
+import {
+ ConsoleGetCompletionTypesResponse,
+ ConsoleRequestBookmarksResponse,
+ ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse
+} from "../../shared/messages";
+import CompletionType from "../../shared/CompletionType";
+
+export type SearchEngines = {
+ title: string
+}
+
+export type BookmarkItem = {
+ title: string
+ url: string
+}
+
+export type HistoryItem = {
+ title: string
+ url: string
+}
+
+export default class CompletionClient {
+ async getCompletionTypes(): Promise<CompletionType[]> {
+ const resp = await browser.runtime.sendMessage({
+ type: messages.CONSOLE_GET_COMPLETION_TYPES,
+ }) as ConsoleGetCompletionTypesResponse;
+ return resp;
+ }
+
+ async requestSearchEngines(query: string): Promise<SearchEngines[]> {
+ const resp = await browser.runtime.sendMessage({
+ type: messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE,
+ query,
+ }) as ConsoleRequestSearchEnginesResponse;
+ return resp;
+ }
+
+ async requestBookmarks(query: string): Promise<BookmarkItem[]> {
+ const resp = await browser.runtime.sendMessage({
+ type: messages.CONSOLE_REQUEST_BOOKMARKS,
+ query,
+ }) as ConsoleRequestBookmarksResponse;
+ return resp;
+ }
+
+ async requestHistory(query: string): Promise<HistoryItem[]> {
+ const resp = await browser.runtime.sendMessage({
+ type: messages.CONSOLE_REQUEST_HISTORY,
+ query,
+ }) as ConsoleRequestHistoryResponse;
+ return resp;
+ }
+}
diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx
index 0a102a0..7be073e 100644
--- a/src/console/components/Console.tsx
+++ b/src/console/components/Console.tsx
@@ -7,6 +7,7 @@ import Message from './console/Message';
import * as consoleActions from '../../console/actions/console';
import { State as AppState } from '../reducers';
import CommandLineParser, { InputPhase } from "../commandline/CommandLineParser";
+import { Command } from "../../shared/Command";
const COMPLETION_MAX_ITEMS = 33;
@@ -163,7 +164,16 @@ class Console extends React.Component<Props> {
if (phase === InputPhase.OnCommand) {
return this.props.dispatch(consoleActions.getCommandCompletions(text));
} else {
- this.props.dispatch(consoleActions.getCompletions(text));
+ const cmd = this.commandLineParser.parse(text);
+ switch (cmd.command) {
+ case Command.Open:
+ case Command.TabOpen:
+ case Command.WindowOpen:
+ this.props.dispatch(consoleActions.getOpenCompletions(this.props.completionTypes, text, cmd.command, cmd.args));
+ break;
+ default:
+ this.props.dispatch(consoleActions.getCompletions(text));
+ }
}
}
}
diff --git a/src/console/index.tsx b/src/console/index.tsx
index 1209ec2..7bee746 100644
--- a/src/console/index.tsx
+++ b/src/console/index.tsx
@@ -22,11 +22,11 @@ window.addEventListener('load', () => {
wrapper);
});
-const onMessage = (message: any): any => {
+const onMessage = async (message: any): Promise<any> => {
const msg = messages.valueOf(message);
switch (msg.type) {
case messages.CONSOLE_SHOW_COMMAND:
- return store.dispatch(consoleActions.showCommand(msg.command));
+ return store.dispatch(await consoleActions.showCommand(msg.command));
case messages.CONSOLE_SHOW_FIND:
return store.dispatch(consoleActions.showFind());
case messages.CONSOLE_SHOW_ERROR:
diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts
index 677a982..f1508bb 100644
--- a/src/console/reducers/index.ts
+++ b/src/console/reducers/index.ts
@@ -1,10 +1,12 @@
import * as actions from '../actions';
import Completions from "../Completions";
+import CompletionType from "../../shared/CompletionType";
export interface State {
mode: string;
messageText: string;
consoleText: string;
+ completionTypes: CompletionType[];
completionSource: string;
completions: Completions;
select: number;
@@ -15,6 +17,7 @@ const defaultState = {
mode: '',
messageText: '',
consoleText: '',
+ completionTypes: [],
completionSource: '',
completions: [],
select: -1,
@@ -69,6 +72,7 @@ export default function reducer(
return { ...state,
mode: 'command',
consoleText: action.text,
+ completionTypes: action.completionTypes,
completions: []};
case actions.CONSOLE_SHOW_FIND:
return { ...state,
diff --git a/src/shared/CompletionType.ts b/src/shared/CompletionType.ts
new file mode 100644
index 0000000..e104455
--- /dev/null
+++ b/src/shared/CompletionType.ts
@@ -0,0 +1,7 @@
+enum CompletionType {
+ SearchEngines,
+ History,
+ Bookmarks,
+}
+
+export default CompletionType; \ No newline at end of file
diff --git a/src/shared/messages.ts b/src/shared/messages.ts
index 7f8bd5b..be6a2e1 100644
--- a/src/shared/messages.ts
+++ b/src/shared/messages.ts
@@ -1,16 +1,21 @@
import * as operations from './operations';
+import CompletionType from "./CompletionType";
export const BACKGROUND_OPERATION = 'background.operation';
export const CONSOLE_UNFOCUS = 'console.unfocus';
export const CONSOLE_ENTER_COMMAND = 'console.enter.command';
export const CONSOLE_ENTER_FIND = 'console.enter.find';
-export const CONSOLE_QUERY_COMPLETIONS = 'console.query.completions';
+export const CONSOLE_QUERY_COMPLETIONS = 'console.query.completions'; // DEPRECATED
export const CONSOLE_SHOW_COMMAND = 'console.show.command';
export const CONSOLE_SHOW_ERROR = 'console.show.error';
export const CONSOLE_SHOW_INFO = 'console.show.info';
export const CONSOLE_SHOW_FIND = 'console.show.find';
export const CONSOLE_HIDE = 'console.hide';
+export const CONSOLE_GET_COMPLETION_TYPES = 'console.get.completion.types'
+export const CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE = 'console.qresut.searchEngines';
+export const CONSOLE_REQUEST_BOOKMARKS = 'console.request.bookmarks';
+export const CONSOLE_REQUEST_HISTORY = 'console.request.history';
export const FOLLOW_START = 'follow.start';
export const FOLLOW_REQUEST_COUNT_TARGETS = 'follow.request.count.targets';
@@ -95,6 +100,41 @@ export interface ConsoleHideMessage {
type: typeof CONSOLE_HIDE;
}
+export interface ConsoleGetCompletionTypesMessage {
+ type: typeof CONSOLE_GET_COMPLETION_TYPES;
+}
+
+export interface ConsoleRequestSearchEnginesMessage {
+ type: typeof CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE;
+ query: string
+}
+
+export interface ConsoleRequestBookmarksMessage {
+ type: typeof CONSOLE_REQUEST_BOOKMARKS;
+ query: string;
+}
+
+export interface ConsoleRequestHistoryMessage {
+ type: typeof CONSOLE_REQUEST_HISTORY;
+ query: string;
+}
+
+export type ConsoleGetCompletionTypesResponse = CompletionType[];
+
+export type ConsoleRequestSearchEnginesResponse = {
+ title: string;
+}[]
+
+export type ConsoleRequestBookmarksResponse = {
+ title: string;
+ url: string;
+}[]
+
+export type ConsoleRequestHistoryResponse = {
+ title: string;
+ url: string;
+}[]
+
export interface FollowStartMessage {
type: typeof FOLLOW_START;
newTab: boolean;
@@ -237,6 +277,10 @@ export type Message =
ConsoleShowInfoMessage |
ConsoleShowFindMessage |
ConsoleHideMessage |
+ ConsoleRequestBookmarksMessage |
+ ConsoleRequestHistoryMessage |
+ ConsoleGetCompletionTypesMessage |
+ ConsoleRequestSearchEnginesMessage |
FollowStartMessage |
FollowRequestCountTargetsMessage |
FollowResponseCountTargetsMessage |