import './console.scss'; import { connect } from 'react-redux'; import React from 'react'; import Input from './console/Input'; import Completion from './console/Completion'; 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; type StateProps = ReturnType; interface DispatchProps { dispatch: (action: any) => void, } type Props = StateProps & DispatchProps; class Console extends React.Component { private input: React.RefObject; private commandLineParser: CommandLineParser = new CommandLineParser(); constructor(props: Props) { super(props); this.input = React.createRef(); } onBlur() { if (this.props.mode === 'command' || this.props.mode === 'find') { return this.props.dispatch(consoleActions.hideCommand()); } } doEnter(e: React.KeyboardEvent) { e.stopPropagation(); e.preventDefault(); const value = (e.target as HTMLInputElement).value; if (this.props.mode === 'command') { return this.props.dispatch(consoleActions.enterCommand(value)); } else if (this.props.mode === 'find') { return this.props.dispatch(consoleActions.enterFind( value === '' ? undefined : value)); } } selectNext(e: React.KeyboardEvent) { this.props.dispatch(consoleActions.completionNext()); e.stopPropagation(); e.preventDefault(); } selectPrev(e: React.KeyboardEvent) { this.props.dispatch(consoleActions.completionPrev()); e.stopPropagation(); e.preventDefault(); } onKeyDown(e: React.KeyboardEvent) { switch (e.key) { case 'Escape': return this.props.dispatch(consoleActions.hideCommand()); case 'Enter': return this.doEnter(e); case 'Tab': if (e.shiftKey) { this.props.dispatch(consoleActions.completionPrev()); } else { this.props.dispatch(consoleActions.completionNext()); } e.stopPropagation(); e.preventDefault(); break; case '[': if (e.ctrlKey) { e.preventDefault(); return this.props.dispatch(consoleActions.hideCommand()); } break; case 'c': if (e.ctrlKey) { e.preventDefault(); return this.props.dispatch(consoleActions.hideCommand()); } break; case 'm': if (e.ctrlKey) { return this.doEnter(e); } break; case 'n': if (e.ctrlKey) { this.selectNext(e); } break; case 'p': if (e.ctrlKey) { this.selectPrev(e); } break; } } onChange(e: React.ChangeEvent) { const text = e.target.value; this.props.dispatch(consoleActions.setConsoleText(text)); if (this.props.mode !== 'command') { return } this.updateCompletions(text) } componentDidUpdate(prevProps: Props) { if (prevProps.mode !== 'command' && this.props.mode === 'command') { this.updateCompletions(this.props.consoleText); this.focus(); } else if (prevProps.mode !== 'find' && this.props.mode === 'find') { this.focus(); } } render() { switch (this.props.mode) { case 'command': case 'find': return
; case 'info': case 'error': return { this.props.messageText } ; default: return null; } } focus() { window.focus(); if (this.input.current) { this.input.current.focus(); } } private updateCompletions(text: string) { const phase = this.commandLineParser.inputPhase(text); if (phase === InputPhase.OnCommand) { return this.props.dispatch(consoleActions.getCommandCompletions(text)); } else { 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)); } } } } const mapStateToProps = (state: AppState) => ({ ...state }); export default connect( mapStateToProps, )(Console);