diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2021-04-04 21:34:13 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2021-04-05 22:21:33 +0900 |
commit | 3a7e55fd292196f600c11fad36425014677a1351 (patch) | |
tree | 53827f62aaea916cf8c76f6d3e08866f1db0d716 /src/console | |
parent | 39f96db5a3187b4ce2e7df529eaa456ee862dd68 (diff) |
Separate Command and Completion reducer
Diffstat (limited to 'src/console')
-rw-r--r-- | src/console/actions/completion.ts | 243 | ||||
-rw-r--r-- | src/console/actions/console.ts | 299 | ||||
-rw-r--r-- | src/console/actions/index.ts | 80 | ||||
-rw-r--r-- | src/console/components/AppContext.ts | 4 | ||||
-rw-r--r-- | src/console/components/CommandPrompt.tsx | 131 | ||||
-rw-r--r-- | src/console/components/Console.tsx | 1 | ||||
-rw-r--r-- | src/console/index.tsx | 2 | ||||
-rw-r--r-- | src/console/reducers/completion.ts | 99 | ||||
-rw-r--r-- | src/console/reducers/console.ts | 64 | ||||
-rw-r--r-- | src/console/reducers/index.ts | 134 |
10 files changed, 567 insertions, 490 deletions
diff --git a/src/console/actions/completion.ts b/src/console/actions/completion.ts new file mode 100644 index 0000000..2f6f82f --- /dev/null +++ b/src/console/actions/completion.ts @@ -0,0 +1,243 @@ +import { Command } from "../../shared/Command"; +import CompletionClient from "../clients/CompletionClient"; +import CompletionType from "../../shared/CompletionType"; +import Completions from "../Completions"; +import TabFlag from "../../shared/TabFlag"; + +const completionClient = new CompletionClient(); + +const commandDocs = { + [Command.Set]: "Set a value of the property", + [Command.Open]: "Open a URL or search by keywords in current tab", + [Command.TabOpen]: "Open a URL or search by keywords in new tab", + [Command.WindowOpen]: "Open a URL or search by keywords in new window", + [Command.Buffer]: "Select tabs by matched keywords", + [Command.BufferDelete]: "Close a certain tab matched by keywords", + [Command.BuffersDelete]: "Close all tabs matched by keywords", + [Command.Quit]: "Close the current tab", + [Command.QuitAll]: "Close all tabs", + [Command.AddBookmark]: "Add current page to bookmarks", + [Command.Help]: "Open Vim Vixen help in new tab", +}; + +const propertyDocs: { [key: string]: string } = { + hintchars: "hint characters on follow mode", + smoothscroll: "smooth scroll", + complete: "which are completed at the open page", + colorscheme: "color scheme of the console", +}; + +export const COMPLETION_START_COMPLETION = "console.start.completion"; +export const COMPLETION_SET_COMPLETIONS = "console.set.completions"; +export const COMPLETION_COMPLETION_NEXT = "completion.completion.next"; +export const COMPLETION_COMPLETION_PREV = "completion.completion.prev"; + +export interface CompletionStartCompletionAction { + type: typeof COMPLETION_START_COMPLETION; + completionTypes: CompletionType[]; +} + +export interface SetCompletionsAction { + type: typeof COMPLETION_SET_COMPLETIONS; + completions: Completions; + completionSource: string; +} + +export interface CompletionNextAction { + type: typeof COMPLETION_COMPLETION_NEXT; +} + +export interface CompletionPrevAction { + type: typeof COMPLETION_COMPLETION_PREV; +} + +export type CompletionAction = + | CompletionStartCompletionAction + | SetCompletionsAction + | CompletionNextAction + | CompletionPrevAction; +const startCompletion = async (): Promise<CompletionStartCompletionAction> => { + const completionTypes = await completionClient.getCompletionTypes(); + return { + type: COMPLETION_START_COMPLETION, + completionTypes, + }; +}; + +const getCommandCompletions = (text: string): SetCompletionsAction => { + const items = Object.entries(commandDocs) + .filter(([name]) => name.startsWith(text.trimLeft())) + .map(([name, doc]) => ({ + caption: name, + content: name, + url: doc, + })); + const completions = [ + { + name: "Console Command", + items, + }, + ]; + return { + type: COMPLETION_SET_COMPLETIONS, + completions, + completionSource: text, + }; +}; + +const getOpenCompletions = async ( + types: CompletionType[], + original: string, + command: Command, + query: string +): Promise<SetCompletionsAction> => { + const completions: Completions = []; + for (const type of types) { + switch (type) { + case CompletionType.SearchEngines: { + const items = await completionClient.requestSearchEngines(query); + if (items.length === 0) { + break; + } + completions.push({ + name: "Search Engines", + items: items.map((key) => ({ + caption: key.title, + content: command + " " + key.title, + })), + }); + break; + } + case CompletionType.History: { + const items = await completionClient.requestHistory(query); + if (items.length === 0) { + break; + } + completions.push({ + name: "History", + items: items.map((item) => ({ + caption: item.title, + content: command + " " + item.url, + url: item.url, + })), + }); + break; + } + case CompletionType.Bookmarks: { + const items = await completionClient.requestBookmarks(query); + if (items.length === 0) { + break; + } + completions.push({ + name: "Bookmarks", + items: items.map((item) => ({ + caption: item.title, + content: command + " " + item.url, + url: item.url, + })), + }); + break; + } + } + } + + return { + type: COMPLETION_SET_COMPLETIONS, + completions, + completionSource: original, + }; +}; + +const getTabCompletions = async ( + original: string, + command: Command, + query: string, + excludePinned: boolean +): Promise<SetCompletionsAction> => { + const items = await completionClient.requestTabs(query, excludePinned); + let completions: Completions = []; + if (items.length > 0) { + completions = [ + { + name: "Buffers", + items: items.map((item) => ({ + content: command + " " + item.url, + caption: `${item.index}: ${ + item.flag != TabFlag.None ? item.flag : " " + } ${item.title}`, + url: item.url, + icon: item.faviconUrl, + })), + }, + ]; + } + return { + type: COMPLETION_SET_COMPLETIONS, + completions, + completionSource: original, + }; +}; + +const getPropertyCompletions = async ( + original: string, + command: Command, + query: string +): Promise<SetCompletionsAction> => { + const properties = await completionClient.getProperties(); + const items = properties + .map((item) => { + const desc = propertyDocs[item.name] || ""; + if (item.type === "boolean") { + return [ + { + caption: item.name, + content: command + " " + item.name, + url: "Enable " + desc, + }, + { + caption: "no" + item.name, + content: command + " no" + item.name, + url: "Disable " + desc, + }, + ]; + } else { + return [ + { + caption: item.name, + content: command + " " + item.name, + url: "Set " + desc, + }, + ]; + } + }) + .reduce((acc, val) => acc.concat(val), []) + .filter((item) => item.caption.startsWith(query)); + const completions: Completions = [{ name: "Properties", items }]; + return { + type: COMPLETION_SET_COMPLETIONS, + completions, + completionSource: original, + }; +}; + +const completionNext = (): CompletionNextAction => { + return { + type: COMPLETION_COMPLETION_NEXT, + }; +}; + +const completionPrev = (): CompletionPrevAction => { + return { + type: COMPLETION_COMPLETION_PREV, + }; +}; + +export { + startCompletion, + getCommandCompletions, + getOpenCompletions, + getTabCompletions, + getPropertyCompletions, + completionNext, + completionPrev, +}; diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts index 16d33b3..646cc31 100644 --- a/src/console/actions/console.ts +++ b/src/console/actions/console.ts @@ -1,72 +1,99 @@ import * as messages from "../../shared/messages"; -import * as actions from "./index"; -import { Command } from "../../shared/Command"; -import CompletionClient from "../clients/CompletionClient"; import SettingClient from "../clients/SettingClient"; -import CompletionType from "../../shared/CompletionType"; -import Completions from "../Completions"; -import TabFlag from "../../shared/TabFlag"; +import ColorScheme from "../../shared/ColorScheme"; -const completionClient = new CompletionClient(); const settingClient = new SettingClient(); -const commandDocs = { - [Command.Set]: "Set a value of the property", - [Command.Open]: "Open a URL or search by keywords in current tab", - [Command.TabOpen]: "Open a URL or search by keywords in new tab", - [Command.WindowOpen]: "Open a URL or search by keywords in new window", - [Command.Buffer]: "Select tabs by matched keywords", - [Command.BufferDelete]: "Close a certain tab matched by keywords", - [Command.BuffersDelete]: "Close all tabs matched by keywords", - [Command.Quit]: "Close the current tab", - [Command.QuitAll]: "Close all tabs", - [Command.AddBookmark]: "Add current page to bookmarks", - [Command.Help]: "Open Vim Vixen help in new tab", -}; - -const propertyDocs: { [key: string]: string } = { - hintchars: "hint characters on follow mode", - smoothscroll: "smooth scroll", - complete: "which are completed at the open page", - colorscheme: "color scheme of the console", -}; - -const hide = (): actions.ConsoleAction => { +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_HIDE_COMMAND = "console.hide.command"; +export const CONSOLE_SET_CONSOLE_TEXT = "console.set.command"; +export const CONSOLE_SHOW_FIND = "console.show.find"; +export const CONSOLE_SET_COLORSCHEME = "completion.set.colorscheme"; +export const CONSOLE_HIDE = "console.hide"; + +export interface HideAction { + type: typeof CONSOLE_HIDE; +} + +export interface ShowCommand { + type: typeof CONSOLE_SHOW_COMMAND; + text: string; +} + +export interface ShowFindAction { + type: typeof CONSOLE_SHOW_FIND; +} + +export interface ShowErrorAction { + type: typeof CONSOLE_SHOW_ERROR; + text: string; +} + +export interface ShowInfoAction { + type: typeof CONSOLE_SHOW_INFO; + text: string; +} + +export interface HideCommandAction { + type: typeof CONSOLE_HIDE_COMMAND; +} + +export interface SetConsoleTextAction { + type: typeof CONSOLE_SET_CONSOLE_TEXT; + consoleText: string; +} + +export interface SetColorSchemeAction { + type: typeof CONSOLE_SET_COLORSCHEME; + colorscheme: ColorScheme; +} + +export type ConsoleAction = + | HideAction + | ShowCommand + | ShowFindAction + | ShowErrorAction + | ShowInfoAction + | HideCommandAction + | SetConsoleTextAction + | SetColorSchemeAction; + +const hide = (): ConsoleAction => { return { - type: actions.CONSOLE_HIDE, + type: CONSOLE_HIDE, }; }; -const showCommand = async (text: string): Promise<actions.ShowCommand> => { - const completionTypes = await completionClient.getCompletionTypes(); +const showCommand = (text: string): ShowCommand => { return { - type: actions.CONSOLE_SHOW_COMMAND, - completionTypes, + type: CONSOLE_SHOW_COMMAND, text, }; }; -const showFind = (): actions.ShowFindAction => { +const showFind = (): ShowFindAction => { return { - type: actions.CONSOLE_SHOW_FIND, + type: CONSOLE_SHOW_FIND, }; }; -const showError = (text: string): actions.ShowErrorAction => { +const showError = (text: string): ShowErrorAction => { return { - type: actions.CONSOLE_SHOW_ERROR, + type: CONSOLE_SHOW_ERROR, text: text, }; }; -const showInfo = (text: string): actions.ShowInfoAction => { +const showInfo = (text: string): ShowInfoAction => { return { - type: actions.CONSOLE_SHOW_INFO, + type: CONSOLE_SHOW_INFO, text: text, }; }; -const hideCommand = (): actions.HideCommandAction => { +const hideCommand = (): HideCommandAction => { window.top.postMessage( JSON.stringify({ type: messages.CONSOLE_UNFOCUS, @@ -74,13 +101,11 @@ const hideCommand = (): actions.HideCommandAction => { "*" ); return { - type: actions.CONSOLE_HIDE_COMMAND, + type: CONSOLE_HIDE_COMMAND, }; }; -const enterCommand = async ( - text: string -): Promise<actions.HideCommandAction> => { +const enterCommand = async (text: string): Promise<HideCommandAction> => { await browser.runtime.sendMessage({ type: messages.CONSOLE_ENTER_COMMAND, text, @@ -88,7 +113,7 @@ const enterCommand = async ( return hideCommand(); }; -const enterFind = (text?: string): actions.HideCommandAction => { +const enterFind = (text?: string): HideCommandAction => { window.top.postMessage( JSON.stringify({ type: messages.CONSOLE_ENTER_FIND, @@ -99,185 +124,17 @@ const enterFind = (text?: string): actions.HideCommandAction => { return hideCommand(); }; -const setConsoleText = (consoleText: string): actions.SetConsoleTextAction => { +const setConsoleText = (consoleText: string): SetConsoleTextAction => { return { - type: actions.CONSOLE_SET_CONSOLE_TEXT, + type: CONSOLE_SET_CONSOLE_TEXT, consoleText, }; }; -const getCommandCompletions = (text: string): actions.SetCompletionsAction => { - const items = Object.entries(commandDocs) - .filter(([name]) => name.startsWith(text.trimLeft())) - .map(([name, doc]) => ({ - caption: name, - content: name, - url: doc, - })); - const completions = [ - { - name: "Console Command", - items, - }, - ]; - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: text, - }; -}; - -const getOpenCompletions = async ( - types: CompletionType[], - original: string, - command: Command, - query: string -): Promise<actions.SetCompletionsAction> => { - const completions: Completions = []; - for (const type of types) { - switch (type) { - case CompletionType.SearchEngines: { - const items = await completionClient.requestSearchEngines(query); - if (items.length === 0) { - break; - } - completions.push({ - name: "Search Engines", - items: items.map((key) => ({ - caption: key.title, - content: command + " " + key.title, - })), - }); - break; - } - case CompletionType.History: { - const items = await completionClient.requestHistory(query); - if (items.length === 0) { - break; - } - completions.push({ - name: "History", - items: items.map((item) => ({ - caption: item.title, - content: command + " " + item.url, - url: item.url, - })), - }); - break; - } - case CompletionType.Bookmarks: { - const items = await completionClient.requestBookmarks(query); - if (items.length === 0) { - break; - } - completions.push({ - name: "Bookmarks", - items: items.map((item) => ({ - caption: item.title, - content: command + " " + item.url, - url: item.url, - })), - }); - break; - } - } - } - - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: original, - }; -}; - -const getTabCompletions = async ( - original: string, - command: Command, - query: string, - excludePinned: boolean -): Promise<actions.SetCompletionsAction> => { - const items = await completionClient.requestTabs(query, excludePinned); - let completions: Completions = []; - if (items.length > 0) { - completions = [ - { - name: "Buffers", - items: items.map((item) => ({ - content: command + " " + item.url, - caption: `${item.index}: ${ - item.flag != TabFlag.None ? item.flag : " " - } ${item.title}`, - url: item.url, - icon: item.faviconUrl, - })), - }, - ]; - } - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: original, - }; -}; - -const getPropertyCompletions = async ( - original: string, - command: Command, - query: string -): Promise<actions.SetCompletionsAction> => { - const properties = await completionClient.getProperties(); - const items = properties - .map((item) => { - const desc = propertyDocs[item.name] || ""; - if (item.type === "boolean") { - return [ - { - caption: item.name, - content: command + " " + item.name, - url: "Enable " + desc, - }, - { - caption: "no" + item.name, - content: command + " no" + item.name, - url: "Disable " + desc, - }, - ]; - } else { - return [ - { - caption: item.name, - content: command + " " + item.name, - url: "Set " + desc, - }, - ]; - } - }) - .reduce((acc, val) => acc.concat(val), []) - .filter((item) => item.caption.startsWith(query)); - const completions: Completions = [{ name: "Properties", items }]; - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: original, - }; -}; - -const completionNext = (): actions.CompletionNextAction => { - return { - type: actions.CONSOLE_COMPLETION_NEXT, - }; -}; - -const completionPrev = (): actions.CompletionPrevAction => { - return { - type: actions.CONSOLE_COMPLETION_PREV, - }; -}; - -const setColorScheme = async (): Promise<actions.SetColorSchemeAction> => { +const setColorScheme = async (): Promise<SetColorSchemeAction> => { const scheme = await settingClient.getColorScheme(); return { - type: actions.CONSOLE_SET_COLORSCHEME, + type: CONSOLE_SET_COLORSCHEME, colorscheme: scheme, }; }; @@ -292,11 +149,5 @@ export { setConsoleText, enterCommand, enterFind, - getCommandCompletions, - getOpenCompletions, - getTabCompletions, - getPropertyCompletions, - completionNext, - completionPrev, setColorScheme, }; diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts deleted file mode 100644 index 6c1c759..0000000 --- a/src/console/actions/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import Completions from "../Completions"; -import CompletionType from "../../shared/CompletionType"; -import ColorScheme from "../../shared/ColorScheme"; - -export const CONSOLE_HIDE = "console.hide"; -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_HIDE_COMMAND = "console.hide.command"; -export const CONSOLE_SET_CONSOLE_TEXT = "console.set.command"; -export const CONSOLE_SET_COMPLETIONS = "console.set.completions"; -export const CONSOLE_COMPLETION_NEXT = "console.completion.next"; -export const CONSOLE_COMPLETION_PREV = "console.completion.prev"; -export const CONSOLE_SHOW_FIND = "console.show.find"; -export const CONSOLE_SET_COLORSCHEME = "console.set.colorscheme"; - -export interface HideAction { - type: typeof CONSOLE_HIDE; -} - -export interface ShowCommand { - type: typeof CONSOLE_SHOW_COMMAND; - text: string; - completionTypes: CompletionType[]; -} - -export interface ShowFindAction { - type: typeof CONSOLE_SHOW_FIND; -} - -export interface ShowErrorAction { - type: typeof CONSOLE_SHOW_ERROR; - text: string; -} - -export interface ShowInfoAction { - type: typeof CONSOLE_SHOW_INFO; - text: string; -} - -export interface HideCommandAction { - type: typeof CONSOLE_HIDE_COMMAND; -} - -export interface SetConsoleTextAction { - type: typeof CONSOLE_SET_CONSOLE_TEXT; - consoleText: string; -} - -export interface SetCompletionsAction { - type: typeof CONSOLE_SET_COMPLETIONS; - completions: Completions; - completionSource: string; -} - -export interface CompletionNextAction { - type: typeof CONSOLE_COMPLETION_NEXT; -} - -export interface CompletionPrevAction { - type: typeof CONSOLE_COMPLETION_PREV; -} - -export interface SetColorSchemeAction { - type: typeof CONSOLE_SET_COLORSCHEME; - colorscheme: ColorScheme; -} - -export type ConsoleAction = - | HideAction - | ShowCommand - | ShowFindAction - | ShowErrorAction - | ShowInfoAction - | HideCommandAction - | SetConsoleTextAction - | SetCompletionsAction - | CompletionNextAction - | CompletionPrevAction - | SetColorSchemeAction; diff --git a/src/console/components/AppContext.ts b/src/console/components/AppContext.ts index 878d00b..a930e14 100644 --- a/src/console/components/AppContext.ts +++ b/src/console/components/AppContext.ts @@ -1,6 +1,6 @@ import React from "react"; -import { State, defaultState } from "../reducers"; -import { ConsoleAction } from "../actions"; +import { State, defaultState } from "../reducers/console"; +import { ConsoleAction } from "../actions/console"; const AppContext = React.createContext<{ state: State; diff --git a/src/console/components/CommandPrompt.tsx b/src/console/components/CommandPrompt.tsx index d69fae6..4e02668 100644 --- a/src/console/components/CommandPrompt.tsx +++ b/src/console/components/CommandPrompt.tsx @@ -1,5 +1,6 @@ import React from "react"; -import * as consoleActions from "../../console/actions/console"; +import * as consoleActions from "../actions/console"; +import * as completionActions from "../actions/completion"; import AppContext from "./AppContext"; import CommandLineParser, { InputPhase, @@ -9,6 +10,8 @@ import ConsoleFrameClient from "../clients/ConsoleFrameClient"; import Input from "./console//Input"; import { Command } from "../../shared/Command"; import styled from "styled-components"; +import reducer, { defaultState, completedText } from "../reducers/completion"; +import CompletionType from "../../shared/CompletionType"; const COMPLETION_MAX_ITEMS = 33; @@ -18,13 +21,15 @@ const ConsoleWrapper = styled.div` const CommandPrompt: React.FC = () => { const { state, dispatch } = React.useContext(AppContext); + const [completionState, completionDispatch] = React.useReducer( + reducer, + defaultState + ); const commandLineParser = new CommandLineParser(); const consoleFrameClient = new ConsoleFrameClient(); const onBlur = () => { - if (state.mode === "command" || state.mode === "find") { - dispatch(consoleActions.hideCommand()); - } + dispatch(consoleActions.hideCommand()); }; const doEnter = (e: React.KeyboardEvent<HTMLInputElement>) => { @@ -32,21 +37,17 @@ const CommandPrompt: React.FC = () => { e.preventDefault(); const value = (e.target as HTMLInputElement).value; - if (state.mode === "command") { - dispatch(consoleActions.enterCommand(value)); - } else if (state.mode === "find") { - dispatch(consoleActions.enterFind(value === "" ? undefined : value)); - } + dispatch(consoleActions.enterCommand(value)); }; const selectNext = (e: React.KeyboardEvent<HTMLInputElement>) => { - dispatch(consoleActions.completionNext()); + completionDispatch(completionActions.completionNext()); e.stopPropagation(); e.preventDefault(); }; const selectPrev = (e: React.KeyboardEvent<HTMLInputElement>) => { - dispatch(consoleActions.completionPrev()); + completionDispatch(completionActions.completionPrev()); e.stopPropagation(); e.preventDefault(); }; @@ -61,9 +62,9 @@ const CommandPrompt: React.FC = () => { break; case "Tab": if (e.shiftKey) { - dispatch(consoleActions.completionPrev()); + completionDispatch(completionActions.completionPrev()); } else { - dispatch(consoleActions.completionNext()); + completionDispatch(completionActions.completionNext()); } e.stopPropagation(); e.preventDefault(); @@ -101,79 +102,113 @@ const CommandPrompt: React.FC = () => { const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { const text = e.target.value; dispatch(consoleActions.setConsoleText(text)); - updateCompletions(text); + const action = getCompletionAction(text); + Promise.resolve(action).then((a) => { + if (a) { + completionDispatch(a); + + const { + scrollWidth: width, + scrollHeight: height, + } = document.getElementById("vimvixen-console")!; + consoleFrameClient.resize(width, height); + } + }); }; React.useEffect(() => { - updateCompletions(state.consoleText); + completionActions.startCompletion().then((action) => { + completionDispatch(action); + + const completionAction = getCompletionAction( + state.consoleText, + action.completionTypes + ); + Promise.resolve(completionAction).then((a) => { + if (a) { + completionDispatch(a); + + const { + scrollWidth: width, + scrollHeight: height, + } = document.getElementById("vimvixen-console")!; + consoleFrameClient.resize(width, height); + } + }); + }); }, []); - React.useEffect(() => { - const { - scrollWidth: width, - scrollHeight: height, - } = document.getElementById("vimvixen-console")!; - consoleFrameClient.resize(width, height); - }); - - const updateCompletions = (text: string) => { + const getCompletionAction = ( + text: string, + completionTypes: CompletionType[] | undefined = undefined + ) => { + const types = completionTypes || completionState.completionTypes; const phase = commandLineParser.inputPhase(text); if (phase === InputPhase.OnCommand) { - dispatch(consoleActions.getCommandCompletions(text)); + return completionActions.getCommandCompletions(text); } else { const cmd = commandLineParser.parse(text); switch (cmd.command) { case Command.Open: case Command.TabOpen: case Command.WindowOpen: - dispatch( - consoleActions.getOpenCompletions( - state.completionTypes, - text, - cmd.command, - cmd.args - ) + return completionActions.getOpenCompletions( + types, + text, + cmd.command, + cmd.args ); - break; case Command.Buffer: - dispatch( - consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + return completionActions.getTabCompletions( + text, + cmd.command, + cmd.args, + false ); - break; case Command.BufferDelete: case Command.BuffersDelete: - dispatch( - consoleActions.getTabCompletions(text, cmd.command, cmd.args, true) + return completionActions.getTabCompletions( + text, + cmd.command, + cmd.args, + true ); - break; case Command.BufferDeleteForce: case Command.BuffersDeleteForce: - dispatch( - consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + return completionActions.getTabCompletions( + text, + cmd.command, + cmd.args, + false ); - break; case Command.Set: - dispatch( - consoleActions.getPropertyCompletions(text, cmd.command, cmd.args) + return completionActions.getPropertyCompletions( + text, + cmd.command, + cmd.args ); - break; } } + return undefined; }; return ( <ConsoleWrapper> <Completion size={COMPLETION_MAX_ITEMS} - completions={state.completions} - select={state.select} + completions={completionState.completions} + select={completionState.select} /> <Input prompt={":"} onBlur={onBlur} onKeyDown={onKeyDown} onChange={onChange} - value={state.consoleText} + value={ + completionState.select < 0 + ? state.consoleText + : completedText(completionState) + } /> </ConsoleWrapper> ); diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx index 8a1f73c..b97ed62 100644 --- a/src/console/components/Console.tsx +++ b/src/console/components/Console.tsx @@ -12,7 +12,6 @@ const Console: React.FC = () => { React.useEffect(() => { dispatch(consoleActions.setColorScheme()); - window.focus(); }, []); const ele = (() => { diff --git a/src/console/index.tsx b/src/console/index.tsx index cf9367b..4a5368b 100644 --- a/src/console/index.tsx +++ b/src/console/index.tsx @@ -1,5 +1,5 @@ import * as messages from "../shared/messages"; -import reducers, { defaultState } from "./reducers"; +import reducers, { defaultState } from "./reducers/console"; import * as consoleActions from "./actions/console"; import Console from "./components/Console"; import AppContext from "./components/AppContext"; diff --git a/src/console/reducers/completion.ts b/src/console/reducers/completion.ts new file mode 100644 index 0000000..2c7ee55 --- /dev/null +++ b/src/console/reducers/completion.ts @@ -0,0 +1,99 @@ +import Completions from "../Completions"; +import CompletionType from "../../shared/CompletionType"; +import { + COMPLETION_COMPLETION_NEXT, + COMPLETION_COMPLETION_PREV, + COMPLETION_SET_COMPLETIONS, + COMPLETION_START_COMPLETION, + CompletionAction, +} from "../actions/completion"; + +export interface State { + completionTypes: CompletionType[]; + completionSource: string; + completions: Completions; + select: number; +} + +export const defaultState = { + completionTypes: [], + completionSource: "", + completions: [], + select: -1, +}; + +const nextSelection = (state: State): number => { + if (state.completions.length === 0) { + return -1; + } + if (state.select < 0) { + return 0; + } + + const length = state.completions + .map((g) => g.items.length) + .reduce((x, y) => x + y); + if (state.select + 1 < length) { + return state.select + 1; + } + return -1; +}; + +const prevSelection = (state: State): number => { + const length = state.completions + .map((g) => g.items.length) + .reduce((x, y) => x + y); + if (state.select < 0) { + return length - 1; + } + return state.select - 1; +}; + +export const completedText = (state: State): string => { + if (state.select < 0) { + return state.completionSource; + } + const items = state.completions + .map((g) => g.items) + .reduce((g1, g2) => g1.concat(g2)); + return items[state.select].content || ""; +}; + +// eslint-disable-next-line max-lines-per-function +export default function reducer( + state: State = defaultState, + action: CompletionAction +): State { + switch (action.type) { + case COMPLETION_START_COMPLETION: + return { + ...state, + completionTypes: action.completionTypes, + completions: [], + select: -1, + }; + case COMPLETION_SET_COMPLETIONS: + return { + ...state, + completions: action.completions, + completionSource: action.completionSource, + select: -1, + }; + case COMPLETION_COMPLETION_NEXT: { + const select = nextSelection(state); + return { + ...state, + select: select, + }; + } + case COMPLETION_COMPLETION_PREV: { + const select = prevSelection(state); + return { + ...state, + select: select, + }; + } + default: + return state; + } +} diff --git a/src/console/reducers/console.ts b/src/console/reducers/console.ts new file mode 100644 index 0000000..3acd0e9 --- /dev/null +++ b/src/console/reducers/console.ts @@ -0,0 +1,64 @@ +import ColorScheme from "../../shared/ColorScheme"; +import { + CONSOLE_HIDE, + CONSOLE_HIDE_COMMAND, + CONSOLE_SET_COLORSCHEME, + CONSOLE_SET_CONSOLE_TEXT, + CONSOLE_SHOW_COMMAND, + CONSOLE_SHOW_ERROR, + CONSOLE_SHOW_FIND, + CONSOLE_SHOW_INFO, + ConsoleAction, +} from "../actions/console"; + +export interface State { + mode: string; + messageText: string; + consoleText: string; + colorscheme: ColorScheme; +} + +export const defaultState = { + mode: "", + messageText: "", + consoleText: "", + colorscheme: ColorScheme.System, +}; + +// eslint-disable-next-line max-lines-per-function +export default function reducer( + state: State = defaultState, + action: ConsoleAction +): State { + switch (action.type) { + case CONSOLE_HIDE: + return { ...state, mode: "" }; + case CONSOLE_SHOW_COMMAND: + return { + ...state, + mode: "command", + consoleText: action.text, + }; + case CONSOLE_SHOW_FIND: + return { ...state, mode: "find", consoleText: "" }; + case CONSOLE_SHOW_ERROR: + return { ...state, mode: "error", messageText: action.text }; + case CONSOLE_SHOW_INFO: + return { ...state, mode: "info", messageText: action.text }; + case CONSOLE_HIDE_COMMAND: + return { + ...state, + mode: + state.mode === "command" || state.mode === "find" ? "" : state.mode, + }; + case CONSOLE_SET_CONSOLE_TEXT: + return { ...state, consoleText: action.consoleText }; + case CONSOLE_SET_COLORSCHEME: + return { + ...state, + colorscheme: action.colorscheme, + }; + default: + return state; + } +} diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts deleted file mode 100644 index 49d0de1..0000000 --- a/src/console/reducers/index.ts +++ /dev/null @@ -1,134 +0,0 @@ -import * as actions from "../actions"; -import Completions from "../Completions"; -import CompletionType from "../../shared/CompletionType"; -import ColorScheme from "../../shared/ColorScheme"; - -export interface State { - mode: string; - messageText: string; - consoleText: string; - completionTypes: CompletionType[]; - completionSource: string; - completions: Completions; - select: number; - colorscheme: ColorScheme; -} - -export const defaultState = { - mode: "", - messageText: "", - consoleText: "", - completionTypes: [], - completionSource: "", - completions: [], - select: -1, - colorscheme: ColorScheme.System, -}; - -const nextSelection = (state: State): number => { - if (state.completions.length === 0) { - return -1; - } - if (state.select < 0) { - return 0; - } - - const length = state.completions - .map((g) => g.items.length) - .reduce((x, y) => x + y); - if (state.select + 1 < length) { - return state.select + 1; - } - return -1; -}; - -const prevSelection = (state: State): number => { - const length = state.completions - .map((g) => g.items.length) - .reduce((x, y) => x + y); - if (state.select < 0) { - return length - 1; - } - return state.select - 1; -}; - -const nextConsoleText = (completions: any[], select: number, defaults: any) => { - if (select < 0) { - return defaults; - } - const items = completions - .map((g) => g.items) - .reduce((g1, g2) => g1.concat(g2)); - return items[select].content; -}; - -// eslint-disable-next-line max-lines-per-function -export default function reducer( - state: State = defaultState, - action: actions.ConsoleAction -): State { - switch (action.type) { - case actions.CONSOLE_HIDE: - return { ...state, mode: "" }; - case actions.CONSOLE_SHOW_COMMAND: - return { - ...state, - mode: "command", - consoleText: action.text, - completionTypes: action.completionTypes, - completions: [], - }; - case actions.CONSOLE_SHOW_FIND: - return { ...state, mode: "find", consoleText: "", completions: [] }; - case actions.CONSOLE_SHOW_ERROR: - return { ...state, mode: "error", messageText: action.text }; - case actions.CONSOLE_SHOW_INFO: - return { ...state, mode: "info", messageText: action.text }; - case actions.CONSOLE_HIDE_COMMAND: - return { - ...state, - mode: - state.mode === "command" || state.mode === "find" ? "" : state.mode, - }; - case actions.CONSOLE_SET_CONSOLE_TEXT: - return { ...state, consoleText: action.consoleText }; - case actions.CONSOLE_SET_COMPLETIONS: - return { - ...state, - completions: action.completions, - completionSource: action.completionSource, - select: -1, - }; - case actions.CONSOLE_COMPLETION_NEXT: { - const select = nextSelection(state); - return { - ...state, - select: select, - consoleText: nextConsoleText( - state.completions, - select, - state.completionSource - ), - }; - } - case actions.CONSOLE_COMPLETION_PREV: { - const select = prevSelection(state); - return { - ...state, - select: select, - consoleText: nextConsoleText( - state.completions, - select, - state.completionSource - ), - }; - } - case actions.CONSOLE_SET_COLORSCHEME: - return { - ...state, - colorscheme: action.colorscheme, - }; - default: - return state; - } -} |