Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/components/IDE/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { Button, IconName, Intent } from '@blueprintjs/core'
* of the editor's content, using `slang`
*/
export interface IControlProps {
isRunning: boolean
handleEvalEditor: () => void
handleEvalRepl: () => void
handleClearReplOutput: () => void
handleInterruptEval: () => void
}

class Control extends React.Component<IControlProps, {}> {
Expand All @@ -30,12 +32,20 @@ class Control extends React.Component<IControlProps, {}> {
{label}
</Button>
)
const runButton = genericButton('Run', 'play', this.props.handleEvalEditor)
const runButton = this.props.isRunning
? null
: genericButton('Run', 'play', this.props.handleEvalEditor)
const stopButton = this.props.isRunning
? genericButton('Stop', 'stop', this.props.handleInterruptEval)
: null
const evalButton = genericButton('Eval', 'play', this.props.handleEvalRepl)
const clearButton = genericButton('Clear', 'remove', this.props.handleClearReplOutput)
return (
<div className="row between-xs">
<div className="col-xs-2">{runButton}</div>
<div className="col-xs-2">
{runButton}
{stopButton}
</div>
<div className="col-xs-4">
<div className="row">
<div className="col-xs-6">{evalButton}</div>
Expand Down
4 changes: 3 additions & 1 deletion src/components/IDE/__tests__/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import Control, { IControlProps } from '../Control'

test('Control renders correctly', () => {
const props: IControlProps = {
isRunning: false,
handleEvalEditor: () => {},
handleEvalRepl: () => {},
handleClearReplOutput: () => {}
handleClearReplOutput: () => {},
handleInterruptEval: () => {}
}
const app = <Control {...props} />
const tree = shallow(app)
Expand Down
13 changes: 10 additions & 3 deletions src/containers/IDE/ControlContainer.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'

import { handleInterruptExecution } from '../../actions/interpreter'
import { clearReplOutput, evalEditor, evalRepl } from '../../actions/playground'
import Control, { IControlProps } from '../../components/IDE/Control'
import { IState } from '../../reducers/states'

type StateProps = Pick<IControlProps, 'isRunning'>

type DispatchProps = Pick<IControlProps, 'handleEvalEditor'> &
Pick<IControlProps, 'handleEvalRepl'> &
Pick<IControlProps, 'handleClearReplOutput'>
Pick<IControlProps, 'handleClearReplOutput'> &
Pick<IControlProps, 'handleInterruptEval'>

/** No-op mapStateToProps */
const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({})
const mapStateToProps: MapStateToProps<StateProps, {}, IState> = state => ({
isRunning: state.playground.isRunning
})

/** Provides a callback function `handleEvalEditor`
* to evaluate code in the Editor.
Expand All @@ -20,7 +26,8 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dis
{
handleEvalEditor: evalEditor,
handleEvalRepl: evalRepl,
handleClearReplOutput: clearReplOutput
handleClearReplOutput: clearReplOutput,
handleInterruptEval: handleInterruptExecution
},
dispatch
)
Expand Down
24 changes: 22 additions & 2 deletions src/reducers/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import {
CLEAR_CONTEXT,
CLEAR_REPL_INPUT,
CLEAR_REPL_OUTPUT,
EVAL_EDITOR,
EVAL_INTERPRETER,
EVAL_INTERPRETER_ERROR,
EVAL_INTERPRETER_SUCCESS,
HANDLE_CONSOLE_LOG,
IAction,
INTERRUPT_EXECUTION,
SEND_REPL_INPUT_TO_OUTPUT,
UPDATE_EDITOR_VALUE,
UPDATE_REPL_VALUE
Expand Down Expand Up @@ -68,6 +71,16 @@ export const reducer: Reducer<IPlaygroundState> = (state = defaultPlayground, ac
...state,
output: newOutput
}
case EVAL_EDITOR:
return {
...state,
isRunning: true
}
case EVAL_INTERPRETER:
return {
...state,
isRunning: true
}
case EVAL_INTERPRETER_SUCCESS:
lastOutput = state.output.slice(-1)[0]
if (lastOutput !== undefined && lastOutput.type === 'running') {
Expand All @@ -83,7 +96,8 @@ export const reducer: Reducer<IPlaygroundState> = (state = defaultPlayground, ac
}
return {
...state,
output: newOutput
output: newOutput,
isRunning: false
}
case EVAL_INTERPRETER_ERROR:
lastOutput = state.output.slice(-1)[0]
Expand All @@ -100,7 +114,13 @@ export const reducer: Reducer<IPlaygroundState> = (state = defaultPlayground, ac
}
return {
...state,
output: newOutput
output: newOutput,
isRunning: false
}
case INTERRUPT_EXECUTION:
return {
...state,
isRunning: false
}
default:
return state
Expand Down
4 changes: 3 additions & 1 deletion src/reducers/states.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface IPlaygroundState {
readonly replValue: string
readonly context: Context
readonly output: InterpreterOutput[]
readonly isRunning: boolean
}

/**
Expand Down Expand Up @@ -90,5 +91,6 @@ export const defaultPlayground: IPlaygroundState = {
editorValue: '',
replValue: '',
context: createContext(),
output: []
output: [],
isRunning: false
}
4 changes: 2 additions & 2 deletions src/sagas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Context, interrupt, runInContext } from '../slang'

import * as actions from '../actions'
import * as actionTypes from '../actions/actionTypes'
import { showWarningMessage } from '../notification'

function* evalCode(code: string, context: Context) {
const { result, interrupted } = yield race({
Expand All @@ -20,6 +21,7 @@ function* evalCode(code: string, context: Context) {
}
} else if (interrupted) {
interrupt(context)
yield call(showWarningMessage, 'Execution aborted by user')
}
}

Expand All @@ -29,7 +31,6 @@ function* interpreterSaga(): SagaIterator {

yield takeEvery(actionTypes.EVAL_EDITOR, function*() {
const code: string = yield select((state: IState) => state.playground.editorValue)
yield put(actions.handleInterruptExecution())
yield put(actions.clearContext())
yield put(actions.clearReplOutput())
context = yield select((state: IState) => state.playground.context)
Expand All @@ -39,7 +40,6 @@ function* interpreterSaga(): SagaIterator {
yield takeEvery(actionTypes.EVAL_REPL, function*() {
const code: string = yield select((state: IState) => state.playground.replValue)
context = yield select((state: IState) => state.playground.context)
yield put(actions.handleInterruptExecution())
yield put(actions.clearReplInput())
yield put(actions.sendReplInputToOutput(code))
yield* evalCode(code, context)
Expand Down