diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-03-26 22:17:00 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-03-26 22:17:00 +0900 |
commit | b2a37b8fc3e273dd71e1e3558c58be8002aa3789 (patch) | |
tree | 9e6f0d354beca92e975dc97462b3860833112f81 | |
parent | 6829e24c62c0291336502b3390905b57b81abd21 (diff) |
Query completions on open command by a completion source
-rw-r--r-- | src/background/completion/CompletionUseCase.ts | 21 | ||||
-rw-r--r-- | src/background/controllers/CompletionController.ts | 31 | ||||
-rw-r--r-- | src/background/infrastructures/ContentMessageListener.ts | 10 | ||||
-rw-r--r-- | src/console/actions/console.ts | 61 | ||||
-rw-r--r-- | src/console/actions/index.ts | 2 | ||||
-rw-r--r-- | src/console/clients/CompletionClient.ts | 54 | ||||
-rw-r--r-- | src/console/components/Console.tsx | 12 | ||||
-rw-r--r-- | src/console/index.tsx | 4 | ||||
-rw-r--r-- | src/console/reducers/index.ts | 4 | ||||
-rw-r--r-- | src/shared/CompletionType.ts | 7 | ||||
-rw-r--r-- | src/shared/messages.ts | 46 |
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 | |