Skip to content

Commit 86eb90a

Browse files
authored
Add Source §2 (#35)
* Rename context.week -> context.chapter * Add list library TODO: Arrow functions do not work with map * Make context chapter 2 by default for dev * Fix arrow funcs not working with map/build_list... * Revert default libraries back to chap 1 * Add sourceChapter property to playground state Playground defaults to most recent source chapter. * Add component for selecting source chapters Not yet wired. * Add action for chapter select Not yet wired up. * Add chapter select * Add section sign, notification on chapter change * Add list.equal
1 parent 2d16621 commit 86eb90a

File tree

15 files changed

+150
-84
lines changed

15 files changed

+150
-84
lines changed

src/actions/actionTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export const CLEAR_REPL_INPUT = 'CLEAR_REPL_INPUT'
1313
export const CLEAR_REPL_OUTPUT = 'CLEAR_REPL_OUTPUT'
1414
export const CLEAR_CONTEXT = 'CLEAR_CONTEXT'
1515
export const SEND_REPL_INPUT_TO_OUTPUT = 'SEND_REPL_INPUT_TO_OUTPUT'
16+
export const CHAPTER_SELECT = 'CHAPTER_SELECT'
17+
export const CHANGE_CHAPTER = 'CHANGE_CHAPTER'
1618

1719
/** Interpreter */
1820
export const HANDLE_CONSOLE_LOG = 'HANDLE_CONSOLE_LOG'

src/actions/playground.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ChangeEvent } from 'react'
12
import { ActionCreator } from 'redux'
23
import * as actionTypes from './actionTypes'
34

@@ -19,6 +20,18 @@ export const sendReplInputToOutput: ActionCreator<actionTypes.IAction> = (newOut
1920
}
2021
})
2122

23+
export const chapterSelect: ActionCreator<actionTypes.IAction> = (
24+
e: ChangeEvent<HTMLSelectElement>
25+
) => ({
26+
type: actionTypes.CHAPTER_SELECT,
27+
payload: e.currentTarget.value
28+
})
29+
30+
export const changeChapter: ActionCreator<actionTypes.IAction> = (newChapter: number) => ({
31+
type: actionTypes.CHANGE_CHAPTER,
32+
payload: newChapter
33+
})
34+
2235
export const evalEditor = () => ({
2336
type: actionTypes.EVAL_EDITOR
2437
})

src/components/IDE/Control.tsx

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { Button, IconName, Intent } from '@blueprintjs/core'
12
import * as React from 'react'
23

3-
import { Button, IconName, Intent } from '@blueprintjs/core'
4+
import { sourceChapters } from '../../reducers/states'
45

56
/**
67
* @property handleEvalEditor - A callback function for evaluation
@@ -10,26 +11,40 @@ export interface IControlProps {
1011
handleEvalEditor: () => void
1112
handleEvalRepl: () => void
1213
handleClearReplOutput: () => void
14+
handleChapterSelect: (e: React.ChangeEvent<HTMLSelectElement>) => void
1315
}
1416

17+
const genericButton = (
18+
label: string,
19+
icon: IconName,
20+
handleClick = () => {},
21+
intent = Intent.NONE,
22+
notMinimal = false
23+
) => (
24+
<Button
25+
onClick={handleClick}
26+
className={(notMinimal ? '' : 'pt-minimal') + ' col-xs-12'}
27+
intent={intent}
28+
icon={icon}
29+
>
30+
{label}
31+
</Button>
32+
)
33+
34+
const chapterSelect = (handleSelect = (e: React.ChangeEvent<HTMLSelectElement>) => {}) => (
35+
<div className="col-xs-4 pt-select pt-select">
36+
<select defaultValue={sourceChapters.slice(-1)[0].toString()} onChange={handleSelect}>
37+
{sourceChapters.map(chap => (
38+
<option key={chap} value={chap}>
39+
{`Source \xa7${chap}`}
40+
</option>
41+
))}
42+
</select>
43+
</div>
44+
)
45+
1546
class Control extends React.Component<IControlProps, {}> {
1647
public render() {
17-
const genericButton = (
18-
label: string,
19-
icon: IconName,
20-
handleClick = () => {},
21-
intent = Intent.NONE,
22-
notMinimal = false
23-
) => (
24-
<Button
25-
onClick={handleClick}
26-
className={(notMinimal ? '' : 'pt-minimal') + ' col-xs-12'}
27-
intent={intent}
28-
icon={icon}
29-
>
30-
{label}
31-
</Button>
32-
)
3348
const runButton = genericButton('Run', 'play', this.props.handleEvalEditor)
3449
const evalButton = genericButton('Eval', 'play', this.props.handleEvalRepl)
3550
const clearButton = genericButton('Clear', 'remove', this.props.handleClearReplOutput)
@@ -38,8 +53,9 @@ class Control extends React.Component<IControlProps, {}> {
3853
<div className="col-xs-2">{runButton}</div>
3954
<div className="col-xs-4">
4055
<div className="row">
41-
<div className="col-xs-6">{evalButton}</div>
42-
<div className="col-xs-6">{clearButton}</div>
56+
{chapterSelect(this.props.handleChapterSelect)}
57+
<div className="col-xs-4">{evalButton}</div>
58+
<div className="col-xs-4">{clearButton}</div>
4359
</div>
4460
</div>
4561
</div>

src/components/IDE/__tests__/Control.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ test('Control renders correctly', () => {
88
const props: IControlProps = {
99
handleEvalEditor: () => {},
1010
handleEvalRepl: () => {},
11-
handleClearReplOutput: () => {}
11+
handleClearReplOutput: () => {},
12+
handleChapterSelect: (e: React.ChangeEvent<HTMLSelectElement>) => {}
1213
}
1314
const app = <Control {...props} />
1415
const tree = shallow(app)

src/components/IDE/__tests__/__snapshots__/Control.tsx.snap

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,22 @@ exports[`Control renders correctly 1`] = `
99
</div>
1010
<div className=\\"col-xs-4\\">
1111
<div className=\\"row\\">
12-
<div className=\\"col-xs-6\\">
12+
<div className=\\"col-xs-4 pt-select pt-select\\">
13+
<select defaultValue=\\"2\\" onChange={[Function: handleChapterSelect]}>
14+
<option value={1}>
15+
Source §1
16+
</option>
17+
<option value={2}>
18+
Source §2
19+
</option>
20+
</select>
21+
</div>
22+
<div className=\\"col-xs-4\\">
1323
<Blueprint2.Button onClick={[Function: handleEvalRepl]} className=\\"pt-minimal col-xs-12\\" intent=\\"none\\" icon=\\"play\\">
1424
Eval
1525
</Blueprint2.Button>
1626
</div>
17-
<div className=\\"col-xs-6\\">
27+
<div className=\\"col-xs-4\\">
1828
<Blueprint2.Button onClick={[Function: handleClearReplOutput]} className=\\"pt-minimal col-xs-12\\" intent=\\"none\\" icon=\\"remove\\">
1929
Clear
2030
</Blueprint2.Button>

src/containers/IDE/ControlContainer.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux'
22
import { bindActionCreators, Dispatch } from 'redux'
33

4-
import { clearReplOutput, evalEditor, evalRepl } from '../../actions/playground'
4+
import { chapterSelect, clearReplOutput, evalEditor, evalRepl } from '../../actions/playground'
55
import Control, { IControlProps } from '../../components/IDE/Control'
66
import { IState } from '../../reducers/states'
77

88
type DispatchProps = Pick<IControlProps, 'handleEvalEditor'> &
99
Pick<IControlProps, 'handleEvalRepl'> &
10-
Pick<IControlProps, 'handleClearReplOutput'>
10+
Pick<IControlProps, 'handleClearReplOutput'> &
11+
Pick<IControlProps, 'handleChapterSelect'>
1112

1213
/** No-op mapStateToProps */
1314
const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({})
@@ -20,7 +21,8 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dis
2021
{
2122
handleEvalEditor: evalEditor,
2223
handleEvalRepl: evalRepl,
23-
handleClearReplOutput: clearReplOutput
24+
handleClearReplOutput: clearReplOutput,
25+
handleChapterSelect: chapterSelect
2426
},
2527
dispatch
2628
)

src/mocks/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createContext } from '../slang'
22
import { Context } from '../slang/types'
33

4-
export function mockContext(): Context {
5-
return createContext()
4+
export function mockContext(chapter = 1): Context {
5+
return createContext(chapter)
66
}

src/reducers/playground.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Reducer } from 'redux'
22
import {
3+
CHANGE_CHAPTER,
34
CLEAR_CONTEXT,
45
CLEAR_REPL_INPUT,
56
CLEAR_REPL_OUTPUT,
@@ -41,7 +42,12 @@ export const reducer: Reducer<IPlaygroundState> = (state = defaultPlayground, ac
4142
case CLEAR_CONTEXT:
4243
return {
4344
...state,
44-
context: createContext()
45+
context: createContext(state.sourceChapter)
46+
}
47+
case CHANGE_CHAPTER:
48+
return {
49+
...state,
50+
sourceChapter: action.payload
4551
}
4652
case HANDLE_CONSOLE_LOG:
4753
/* Possible cases:

src/reducers/states.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ export interface IApplicationState {
1111
readonly environment: ApplicationEnvironment
1212
}
1313

14+
export const sourceChapters = [1, 2]
15+
const latestSourceChapter = sourceChapters.slice(-1)[0]
16+
1417
export interface IPlaygroundState {
18+
readonly sourceChapter: number
1519
readonly editorValue: string
1620
readonly replValue: string
1721
readonly context: Context
@@ -87,8 +91,9 @@ export const defaultApplication: IApplicationState = {
8791
}
8892

8993
export const defaultPlayground: IPlaygroundState = {
94+
sourceChapter: latestSourceChapter,
9095
editorValue: '',
9196
replValue: '',
92-
context: createContext(),
97+
context: createContext(latestSourceChapter),
9398
output: []
9499
}

src/sagas/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Context, interrupt, runInContext } from '../slang'
66

77
import * as actions from '../actions'
88
import * as actionTypes from '../actions/actionTypes'
9+
import { showSuccessMessage } from '../notification'
910

1011
function* evalCode(code: string, context: Context) {
1112
const { result, interrupted } = yield race({
@@ -44,6 +45,20 @@ function* interpreterSaga(): SagaIterator {
4445
yield put(actions.sendReplInputToOutput(code))
4546
yield* evalCode(code, context)
4647
})
48+
49+
yield takeEvery(actionTypes.CHAPTER_SELECT, function*(action) {
50+
const newChapter = parseInt((action as actionTypes.IAction).payload, 10)
51+
const oldChapter = yield select((state: IState) => state.playground.sourceChapter)
52+
if (newChapter !== oldChapter) {
53+
yield put(actions.changeChapter(newChapter))
54+
yield put(actions.handleInterruptExecution())
55+
yield put(actions.clearContext())
56+
yield put(actions.clearReplOutput())
57+
yield call(showSuccessMessage, `Switched to Source \xa7${newChapter}`)
58+
} else {
59+
yield undefined
60+
}
61+
})
4762
}
4863

4964
function* mainSaga() {

0 commit comments

Comments
 (0)