Simplify bitwisecmm (#16)

This commit is contained in:
Borys Levytskyi
2021-01-14 20:07:59 +02:00
committed by GitHub
parent 49e5265985
commit f671b32b63
16 changed files with 85 additions and 193 deletions

View File

@@ -1,12 +1,11 @@
import React from 'react'; import React from 'react';
import InputBox from './components/InputBox'; import InputBox from './components/InputBox';
import DisplayResultView from './components/DisplayResultView'; import DisplayResultView from './components/DisplayResultView';
import AppState from './core/AppState'; import AppState, { CommandResultView } from './core/AppState';
import cmd from './core/cmd'; import cmd from './core/cmd';
import CommandResult from './models/CommandResult';
import log from 'loglevel'; import log from 'loglevel';
import Indicators from './components/Indicators'; import Indicators from './components/Indicators';
import CommandLink from './components/CommandLink'; import hash from './core/hash';
type AppRootProps = { type AppRootProps = {
appState: AppState, appState: AppState,
@@ -15,7 +14,7 @@ type AppRootProps = {
type AppRootState = { type AppRootState = {
uiTheme: string, uiTheme: string,
emphasizeBytes: boolean, emphasizeBytes: boolean,
commandResults: CommandResult[] commandResults: CommandResultView[]
} }
export default class AppRoot extends React.Component<AppRootProps, AppRootState> { export default class AppRoot extends React.Component<AppRootProps, AppRootState> {
@@ -35,7 +34,10 @@ export default class AppRoot extends React.Component<AppRootProps, AppRootState>
getResultViews() : JSX.Element[] { getResultViews() : JSX.Element[] {
log.debug('getting result views') log.debug('getting result views')
var results = this.state.commandResults.map((r, i) => <DisplayResultView key={i} content={r} input={r.input} inputHash={r.inputHash} appState={this.props.appState} />); var results = this.state.commandResults.map((r, i) =>
<DisplayResultView key={r.key} input={r.input} inputHash={hash.encodeHash(r.input)} appState={this.props.appState}>
{r.view}
</DisplayResultView>);
return results; return results;
} }
@@ -66,7 +68,7 @@ export default class AppRoot extends React.Component<AppRootProps, AppRootState>
<InputBox onCommandEntered={(input) => cmd.execute(input)} /> <InputBox onCommandEntered={(input) => cmd.execute(input)} />
<span className="configPnl"> <span className="configPnl">
<span id="emphasizeBytes" data-cmd="em" className={"indicator " + this.getIndicator(this.state.emphasizeBytes)} title="Toggle Emphasize Bytes" onClick={e => this.toggleEmphasizeBytes()}>[em]</span> <span id="emphasizeBytes" data-cmd="em" className={"indicator " + this.getIndicator(this.state.emphasizeBytes)} title="Toggle Emphasize Bytes" onClick={() => this.toggleEmphasizeBytes()}>[em]</span>
</span> </span>
</div> </div>

View File

@@ -1,18 +1,17 @@
import HelpResult from './models/HelpResult';
import AboutResult from './models/AboutResult';
import UnknownCommandResult from './models/UnknownCommandResult';
import ExpressionResult from './models/ExpressionResult';
import {UnhandledErrorResult, ErrorResult} from './models/ErrorResults';
import WahtsnewResult from './models/WhatsnewResult';
import StringResult from './models/StringResult';
import * as expression from './expression/expression'; import * as expression from './expression/expression';
import React from 'react';
import uuid from 'uuid/v4'; import uuid from 'uuid/v4';
import { CommandInput, CmdShell } from './core/cmd'; import { CommandInput, CmdShell } from './core/cmd';
import { ExpressionInput } from './expression/expression-interfaces';
import AppState from './core/AppState'; import AppState from './core/AppState';
import {ParsingError, IpAddress, ipAddressParser, IpAddressWithSubnetMask, ParsedIpObject} from './ipaddress/ip' import {ParsingError, IpAddress, ipAddressParser, IpAddressWithSubnetMask, ParsedIpObject} from './ipaddress/ip'
import IpAddressResult from './models/IpAddressResult'; import ErrorResultView from './components/results/ErrorResultView';
import { isGetAccessor, isPrefixUnaryExpression } from 'typescript'; import HelpResultView from './components/results/HelpResultView';
import AboutResultView from './components/results/AboutResultView';
import WhatsnewResultView from './components/results/WhatsNewResultView';
import TextResultView from './components/results/TextResultView';
import IpAddressView from './components/results/IpAddressView';
import UnknownInputResultView from './components/results/UnknownInputResultView';
import BitwiseOperationExpressionView from './components/results/expressions/BitwiseOperationExpressionView';
export default { export default {
initialize (cmd: CmdShell, appState: AppState) { initialize (cmd: CmdShell, appState: AppState) {
@@ -20,19 +19,19 @@ export default {
cmd.debugMode = appState.debugMode; cmd.debugMode = appState.debugMode;
appState.onChange(() => cmd.debugMode = appState.debugMode); appState.onChange(() => cmd.debugMode = appState.debugMode);
cmd.command("help", (c: CommandInput) => appState.addCommandResult(new HelpResult(c.input))); cmd.command("help", (c: CommandInput) => appState.addCommandResult(c.input, <HelpResultView />));
cmd.command("clear", (c: CommandInput) => appState.clearCommandResults()); cmd.command("clear", () => appState.clearCommandResults());
cmd.command("em", (c: CommandInput) => appState.toggleEmphasizeBytes()); cmd.command("em", () => appState.toggleEmphasizeBytes());
cmd.command("dark", (c: CommandInput) => appState.setUiTheme('dark')); cmd.command("dark", () => appState.setUiTheme('dark'));
cmd.command("light", (c: CommandInput) => appState.setUiTheme('light')); cmd.command("light", () => appState.setUiTheme('light'));
cmd.command("midnight", (c: CommandInput) => appState.setUiTheme('midnight')); cmd.command("midnight", () => appState.setUiTheme('midnight'));
cmd.command("about", (c: CommandInput) => appState.addCommandResult(new AboutResult(c.input))); cmd.command("about", (c: CommandInput) => appState.addCommandResult(c.input, <AboutResultView />));
cmd.command("whatsnew", (c: CommandInput) => appState.addCommandResult(new WahtsnewResult(c.input))); cmd.command("whatsnew", (c: CommandInput) => appState.addCommandResult(c.input, <WhatsnewResultView />));
cmd.command("guid", (c: CommandInput) => appState.addCommandResult(new StringResult(c.input, uuid()))); cmd.command("guid", (c: CommandInput) => appState.addCommandResult(c.input, <TextResultView text={uuid()} />));
cmd.command("-notrack", (c: CommandInput) => {}); cmd.command("-notrack", () => {});
cmd.command("-debug", (c: CommandInput) => { cmd.command("-debug", (c: CommandInput) => {
appState.toggleDebugMode(); appState.toggleDebugMode();
appState.addCommandResult(new StringResult(c.input, `Debug Mode: ${appState.debugMode}`)) appState.addCommandResult(c.input, <TextResultView text={`Debug Mode: ${appState.debugMode}`}/>);
}); });
@@ -46,7 +45,7 @@ export default {
return; return;
if(result instanceof ParsingError) { if(result instanceof ParsingError) {
appState.addCommandResult(new ErrorResult(c.input, result.errorMessage)); appState.addCommandResult(c.input, <ErrorResultView errorMessage={result.errorMessage} />);
return; return;
} }
@@ -63,7 +62,7 @@ export default {
} }
}); });
appState.addCommandResult(new IpAddressResult(c.input, ipAddresses)); appState.addCommandResult(c.input, <IpAddressView ipAddresses={ipAddresses} />);
} }
}) })
@@ -72,16 +71,16 @@ export default {
canHandle: (input:string) => expression.parser.canParse(input), canHandle: (input:string) => expression.parser.canParse(input),
handle: function(c: CommandInput) { handle: function(c: CommandInput) {
var expr = expression.parser.parse(c.input); var expr = expression.parser.parse(c.input);
appState.addCommandResult(new ExpressionResult(c.input, expr as ExpressionInput)); appState.addCommandResult(c.input, <BitwiseOperationExpressionView expression={expr!} emphasizeBytes={appState.emphasizeBytes} />);
} }
}) })
// Last command handler reports that input is unknown // Last command handler reports that input is unknown
cmd.command({ cmd.command({
canHandle: () => true, canHandle: () => true,
handle: (c: CommandInput) => appState.addCommandResult(new UnknownCommandResult(c.input)) handle: (c: CommandInput) => appState.addCommandResult(c.input, <UnknownInputResultView input={c.input}/>)
}); });
cmd.onError((input: string, err: Error) => appState.addCommandResult(new UnhandledErrorResult(input, err))); cmd.onError((input: string, err: Error) => appState.addCommandResult(input, <ErrorResultView errorMessage={err.toString()} />));
} }
} }

View File

@@ -1,81 +1,23 @@
import React from 'react'; import React from 'react';
import HelpResult from '../models/HelpResult';
import AboutResult from '../models/AboutResult';
import HelpResultView from './results/HelpResultView';
import AboutResultView from './results/AboutResultView';
import ExpressionResult from '../models/ExpressionResult';
import BitwiseOperationExpressionView from './results/expressions/BitwiseOperationExpressionView';
import WhatsnewResult from '../models/WhatsnewResult';
import WhatsnewResultView from './results/WhatsNewResultView';
import {UnhandledErrorResult, ErrorResult} from '../models/ErrorResults';
import StringResult from '../models/StringResult';
import IpAddressView from './results/IpAddressView';
import CommandResult from '../models/CommandResult';
import AppState from '../core/AppState'; import AppState from '../core/AppState';
import IpAddressResult from '../models/IpAddressResult';
type DisplayResultProps = { type DisplayResultProps = {
content : CommandResult,
appState: AppState, appState: AppState,
inputHash: string, inputHash: string,
input: string, input: string,
key: number key: number
} }
export default class DisplayResult extends React.Component<DisplayResultProps> { export default class DisplayResultView extends React.Component<DisplayResultProps> {
render() { render() {
return <div className="result"> return <div className="result">
<div className="input mono"><span className="cur">&gt;</span>{this.props.content.input}<a className="hashLink" title="Link for this expression" href={window.location.pathname + '#' + this.props.inputHash}>#</a></div> <div className="input mono"><span className="cur">&gt;</span>{this.props.input}<a className="hashLink" title="Link for this expression" href={window.location.pathname + '#' + this.props.inputHash}>#</a></div>
<div className="content"> <div className="content">
{this.findResultComponent(this.props.content)} {this.props.children}
</div> </div>
</div>; </div>;
} }
}
findResultComponent(result: CommandResult) : JSX.Element {
if(result instanceof HelpResult) {
return <HelpResultView />
}
if(result instanceof AboutResult) {
return <AboutResultView />
}
if(result instanceof ExpressionResult) {
return <BitwiseOperationExpressionView expression={result.expression} emphasizeBytes={this.props.appState.emphasizeBytes} />
}
if(result instanceof WhatsnewResult) {
return <WhatsnewResultView />
}
if(result instanceof StringResult) {
return <p>{result.value}</p>
}
if (result instanceof UnhandledErrorResult) {
return <div className="result">
<div className="error">(X_X) Ooops.. Something ain' right: <strong>{result.error.message}</strong></div>
</div>
}
if (result instanceof ErrorResult) {
return <div className="result">
<div className="error">{result.errorMessage}</div>
</div>
}
if(result instanceof IpAddressResult) {
const ipResult = result as IpAddressResult;
return <IpAddressView ipAddresses={ipResult.ipAddresses} />
}
return <div className="result">
<div className="error">¯\_()_/¯ Sorry, i don&prime;t know what <strong>{this.props.content.input}</strong> is</div>
</div>
}
}

View File

@@ -0,0 +1,10 @@
import React from 'react';
function ErrorResultView(props : {errorMessage:string}) {
return <div className="result">
<div className="error">{props.errorMessage}</div>
</div>;
}
export default ErrorResultView;

View File

@@ -0,0 +1,7 @@
import React from 'react';
function TextResultView(props : { text: string }) {
return <p>{props.text}</p>;
}
export default TextResultView;

View File

@@ -0,0 +1,10 @@
import React from 'react';
function UnknownInputResultView(props : {input:string}) {
return <div className="result">
<div className="error">¯\_()_/¯ Sorry, i don&prime;t know what <strong>{props.input}</strong> is</div>
</div>;
}
export default UnknownInputResultView;

View File

@@ -9,6 +9,12 @@ export type PersistedAppData = {
debugMode: boolean | null; debugMode: boolean | null;
} }
export type CommandResultView = {
key: number,
input: string,
view: JSX.Element
};
export type AppStateChangeHandler = (state: AppState) => void; export type AppStateChangeHandler = (state: AppState) => void;
export default class AppState { export default class AppState {
@@ -17,15 +23,15 @@ export default class AppState {
emphasizeBytes: boolean; emphasizeBytes: boolean;
debugMode: boolean = false; debugMode: boolean = false;
uiTheme: string; uiTheme: string;
handlers: AppStateChangeHandler[]; changeHandlers: AppStateChangeHandler[];
commandResults: any[]; commandResults: CommandResultView[];
persistedVersion: number; persistedVersion: number;
wasOldVersion: boolean; wasOldVersion: boolean;
env: string; env: string;
constructor(persistData : PersistedAppData, env: string) { constructor(persistData : PersistedAppData, env: string) {
this.commandResults = []; this.commandResults = [];
this.handlers = []; this.changeHandlers = [];
this.uiTheme = persistData.uiTheme || 'midnight'; this.uiTheme = persistData.uiTheme || 'midnight';
this.env = env; this.env = env;
@@ -35,9 +41,10 @@ export default class AppState {
this.debugMode = env !== 'prod' || persistData.debugMode === true; this.debugMode = env !== 'prod' || persistData.debugMode === true;
} }
addCommandResult(result : any) { addCommandResult(input : string, view : JSX.Element) {
this.commandResults.unshift(result); const key = generateKey();
log.debug("result added", result); this.commandResults.unshift({key, input, view});
log.debug(`command result added: ${input}`);
this.triggerChanged(); this.triggerChanged();
} }
@@ -52,11 +59,11 @@ export default class AppState {
} }
onChange(handler : AppStateChangeHandler) { onChange(handler : AppStateChangeHandler) {
this.handlers.push(handler); this.changeHandlers.push(handler);
} }
triggerChanged() { triggerChanged() {
this.handlers.forEach(h => h(this)); this.changeHandlers.forEach(h => h(this));
} }
setUiTheme(theme: string) { setUiTheme(theme: string) {
@@ -77,4 +84,8 @@ export default class AppState {
debugMode: this.debugMode debugMode: this.debugMode
} }
} }
}; };
function generateKey() : number {
return Math.ceil(Math.random()*10000000) ^ Date.now(); // Because why the hell not...
}

View File

@@ -1,7 +0,0 @@
import CommandResult from './CommandResult';
export default class AboutResult extends CommandResult {
constructor(input:string) {
super(input);
}
}

View File

@@ -1,13 +0,0 @@
export default class CommandResult {
input: string;
inputHash: string;
constructor(input: string) {
this.input = input;
this.inputHash = this.encodeHash(input);
}
encodeHash (input: string) {
return encodeURI(input.trim().replace(/\s/g,','));
}
}

View File

@@ -1,17 +0,0 @@
import CommandResult from './CommandResult';
export class UnhandledErrorResult extends CommandResult {
error: Error;
constructor(input: string, error : Error) {
super(input);
this.error = error;
}
}
export class ErrorResult extends CommandResult {
errorMessage: string;
constructor(input: string, errorMessage : string) {
super(input);
this.errorMessage = errorMessage;
}
}

View File

@@ -1,10 +0,0 @@
import CommandResult from './CommandResult';
import { ExpressionInput } from '../expression/expression-interfaces';
export default class ExpressionResult extends CommandResult {
expression: ExpressionInput;
constructor(input: string, expression: ExpressionInput) {
super(input);
this.expression = expression;
}
}

View File

@@ -1,7 +0,0 @@
import CommandResult from './CommandResult';
export default class HelpResult extends CommandResult {
constructor(input: string) {
super(input);
}
}

View File

@@ -1,10 +0,0 @@
import { IpAddress, ipAddressParser, IpAddressWithSubnetMask } from '../ipaddress/ip';
import CommandResult from './CommandResult';
export default class IpAddressResult extends CommandResult {
ipAddresses: IpAddress[];
constructor(input: string, ipAddresses: IpAddress[]) {
super(input);
this.ipAddresses = ipAddresses;
}
}

View File

@@ -1,9 +0,0 @@
import CommandResult from './CommandResult';
export default class StringResult extends CommandResult {
value:string;
constructor(input: string, value : string) {
super(input);
this.value = value;
}
}

View File

@@ -1,9 +0,0 @@
import CommandResult from './CommandResult';
export default class UnknownCommandResult extends CommandResult {
message:string;
constructor(input : string) {
super(input);
this.message = `Sorry, i don''t know what ${input} is :(`;
}
}

View File

@@ -1,7 +0,0 @@
import CommandResult from './CommandResult';
export default class WhatsnewResult extends CommandResult {
constructor(input: string) {
super(input);
}
}