Skip to content

Commit 7d81334

Browse files
authored
Implement history search in repl via up/down arrows (#200)
* Add property replHistory to workspace state * Define actions, ActionCreators for ReplHistory * Remove reducer cases for EVAL_[REPL|EDITOR] * Push codeOutput to replHistory in workspace reducer * Add keyboard shortcuts in ReplInput * Connect dispatches for browse repl to workspaces * Implement up/down arrow behaviours * Rename property isBrowsingIndex -> browseIndex * Prevent saving of empty replValues into replHistory * Revert removal of EVAL_EDITOR and EVAL_REPL reducers * Use variable for max repl history length
1 parent 8bf06b6 commit 7d81334

File tree

16 files changed

+222
-30
lines changed

16 files changed

+222
-30
lines changed

src/actions/actionTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export const EVAL_INTERPRETER_SUCCESS = 'EVAL_INTERPRETER_SUCCESS'
1919
export const HANDLE_CONSOLE_LOG = 'HANDLE_CONSOLE_LOG'
2020

2121
/** Workspace */
22+
export const BROWSE_REPL_HISTORY_DOWN = 'BROWSE_REPL_HISTORY_DOWN'
23+
export const BROWSE_REPL_HISTORY_UP = 'BROWSE_REPL_HISTORY_UP'
2224
export const CHANGE_ACTIVE_TAB = 'CHANGE_ACTIVE_TAB'
2325
export const CHANGE_EDITOR_WIDTH = 'CHANGE_EDITOR_WIDTH'
2426
export const CHANGE_PLAYGROUND_EXTERNAL = 'CHANGE_PLAYGROUND_EXTERNAL'

src/actions/workspaces.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,23 @@ export enum WorkspaceLocations {
1515
assessment = 'assessment',
1616
playground = 'playground'
1717
}
18+
1819
export type WorkspaceLocation = keyof typeof WorkspaceLocations
1920

21+
export const browseReplHistoryDown: ActionCreator<actionTypes.IAction> = (
22+
workspaceLocation: WorkspaceLocation
23+
) => ({
24+
type: actionTypes.BROWSE_REPL_HISTORY_DOWN,
25+
payload: { workspaceLocation }
26+
})
27+
28+
export const browseReplHistoryUp: ActionCreator<actionTypes.IAction> = (
29+
workspaceLocation: WorkspaceLocation
30+
) => ({
31+
type: actionTypes.BROWSE_REPL_HISTORY_UP,
32+
payload: { workspaceLocation }
33+
})
34+
2035
export const changeActiveTab: ActionCreator<actionTypes.IAction> = (
2136
activeTab: number,
2237
workspaceLocation: WorkspaceLocation

src/components/Playground.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface IStateProps {
2424
}
2525

2626
export interface IDispatchProps {
27+
handleBrowseHistoryDown: () => void
28+
handleBrowseHistoryUp: () => void
2729
handleChangeActiveTab: (activeTab: number) => void
2830
handleChapterSelect: (chapter: any, changeEvent: any) => void
2931
handleEditorEval: () => void
@@ -85,6 +87,8 @@ class Playground extends React.Component<IPlaygroundProps, PlaygroundState> {
8587
replProps: {
8688
output: this.props.output,
8789
replValue: this.props.replValue,
90+
handleBrowseHistoryDown: this.props.handleBrowseHistoryDown,
91+
handleBrowseHistoryUp: this.props.handleBrowseHistoryUp,
8892
handleReplEval: this.props.handleReplEval,
8993
handleReplValueChange: this.props.handleReplValueChange
9094
},

src/components/__tests__/Playground.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ const baseProps = {
1515
externalLibrary: 'none',
1616
output: [],
1717
replValue: '',
18-
handleChapterSelect: (chapter: any, e: any) => {},
19-
handleExternalSelect: (external: any, e: any) => {},
18+
handleBrowseHistoryDown: () => {},
19+
handleBrowseHistoryUp: () => {},
2020
handleChangeActiveTab: (n: number) => {},
21+
handleChapterSelect: (chapter: any, e: any) => {},
2122
handleEditorEval: () => {},
2223
handleEditorValueChange: () => {},
2324
handleEditorWidthChange: (widthChange: number) => {},
25+
handleExternalSelect: (external: any, e: any) => {},
2426
handleGenerateLz: () => {},
2527
handleInterruptEval: () => {},
2628
handleReplEval: () => {},

src/components/academy/grading/GradingWorkspace.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ export type OwnProps = {
3737
}
3838

3939
export type DispatchProps = {
40-
handleGradingFetch: (submissionId: number) => void
40+
handleBrowseHistoryDown: () => void
41+
handleBrowseHistoryUp: () => void
4142
handleChangeActiveTab: (activeTab: number) => void
4243
handleChapterSelect: (chapter: any, changeEvent: any) => void
4344
handleClearContext: (chapter: number, externals: string[]) => void
4445
handleEditorEval: () => void
4546
handleEditorValueChange: (val: string) => void
4647
handleEditorWidthChange: (widthChange: number) => void
48+
handleGradingFetch: (submissionId: number) => void
4749
handleInterruptEval: () => void
4850
handleReplEval: () => void
4951
handleReplOutputClear: () => void
@@ -97,10 +99,12 @@ class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
9799
sideContentHeight: this.props.sideContentHeight,
98100
sideContentProps: this.sideContentProps(this.props, questionId),
99101
replProps: {
100-
output: this.props.output,
101-
replValue: this.props.replValue,
102+
handleBrowseHistoryDown: this.props.handleBrowseHistoryDown,
103+
handleBrowseHistoryUp: this.props.handleBrowseHistoryUp,
102104
handleReplEval: this.props.handleReplEval,
103-
handleReplValueChange: this.props.handleReplValueChange
105+
handleReplValueChange: this.props.handleReplValueChange,
106+
output: this.props.output,
107+
replValue: this.props.replValue
104108
}
105109
}
106110
return (

src/components/assessment/AssessmentWorkspace.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export type OwnProps = {
4040

4141
export type DispatchProps = {
4242
handleAssessmentFetch: (assessmentId: number) => void
43+
handleBrowseHistoryDown: () => void
44+
handleBrowseHistoryUp: () => void
4345
handleChangeActiveTab: (activeTab: number) => void
4446
handleChapterSelect: (chapter: any, changeEvent: any) => void
4547
handleClearContext: (chapter: number, externals: string[]) => void
@@ -119,10 +121,12 @@ class AssessmentWorkspace extends React.Component<
119121
sideContentHeight: this.props.sideContentHeight,
120122
sideContentProps: this.sideContentProps(this.props, questionId),
121123
replProps: {
122-
output: this.props.output,
123-
replValue: this.props.replValue,
124+
handleBrowseHistoryDown: this.props.handleBrowseHistoryDown,
125+
handleBrowseHistoryUp: this.props.handleBrowseHistoryUp,
124126
handleReplEval: this.props.handleReplEval,
125-
handleReplValueChange: this.props.handleReplValueChange
127+
handleReplValueChange: this.props.handleReplValueChange,
128+
output: this.props.output,
129+
replValue: this.props.replValue
126130
}
127131
}
128132
return (
@@ -195,6 +199,7 @@ class AssessmentWorkspace extends React.Component<
195199
handleInterruptEval: this.props.handleInterruptEval,
196200
handleReplEval: this.props.handleReplEval,
197201
handleReplOutputClear: this.props.handleReplOutputClear,
202+
handleReplValueChange: this.props.handleReplValueChange,
198203
hasChapterSelect: false,
199204
hasDoneButton: questionId === this.props.assessment!.questions.length - 1,
200205
hasNextButton: questionId < this.props.assessment!.questions.length - 1,

src/components/assessment/__tests__/AssessmentWorkspace.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const defaultProps: AssessmentWorkspaceProps = {
1010
closeDate: '2048-06-18T05:24:26.026Z',
1111
editorWidth: '50%',
1212
handleAssessmentFetch: (assessmentId: number) => {},
13+
handleBrowseHistoryDown: () => {},
14+
handleBrowseHistoryUp: () => {},
1315
handleChangeActiveTab: (activeTab: number) => {},
1416
handleChapterSelect: (chapter: any, changeEvent: any) => {},
1517
handleClearContext: (chapter: number, externals: string[]) => {},

src/components/workspace/Repl.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import ReplInput, { IReplInputProps } from './ReplInput'
99
export interface IReplProps {
1010
output: InterpreterOutput[]
1111
replValue: string
12+
handleBrowseHistoryDown: () => void
13+
handleBrowseHistoryUp: () => void
1214
handleReplEval: () => void
1315
handleReplValueChange: (newCode: string) => void
1416
}

src/components/workspace/ReplInput.tsx

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,27 @@ import 'brace/theme/terminal'
66

77
export interface IReplInputProps {
88
replValue: string
9+
handleBrowseHistoryDown: () => void
10+
handleBrowseHistoryUp: () => void
911
handleReplValueChange: (newCode: string) => void
1012
handleReplEval: () => void
1113
}
1214

1315
class ReplInput extends React.PureComponent<IReplInputProps, {}> {
1416
private replInputBottom: HTMLDivElement
17+
private execBrowseHistoryDown: () => void
18+
private execBrowseHistoryUp: () => void
19+
private execEvaluate: () => void
20+
21+
constructor(props: IReplInputProps) {
22+
super(props)
23+
this.execBrowseHistoryDown = props.handleBrowseHistoryDown
24+
this.execBrowseHistoryUp = props.handleBrowseHistoryUp
25+
this.execEvaluate = () => {
26+
this.replInputBottom.scrollIntoView()
27+
this.props.handleReplEval()
28+
}
29+
}
1530

1631
public componentDidUpdate() {
1732
if (this.replInputBottom.clientWidth >= window.innerWidth - 50) {
@@ -41,16 +56,29 @@ class ReplInput extends React.PureComponent<IReplInputProps, {}> {
4156
value={this.props.replValue}
4257
onChange={this.props.handleReplValueChange}
4358
commands={[
59+
{
60+
name: 'browseHistoryDown',
61+
bindKey: {
62+
win: 'Down',
63+
mac: 'Down'
64+
},
65+
exec: this.execBrowseHistoryDown
66+
},
67+
{
68+
name: 'browseHistoryUp',
69+
bindKey: {
70+
win: 'Up',
71+
mac: 'Up'
72+
},
73+
exec: this.execBrowseHistoryUp
74+
},
4475
{
4576
name: 'evaluate',
4677
bindKey: {
4778
win: 'Shift-Enter',
4879
mac: 'Shift-Enter'
4980
},
50-
exec: () => {
51-
this.replInputBottom.scrollIntoView()
52-
this.props.handleReplEval()
53-
}
81+
exec: this.execEvaluate
5482
}
5583
]}
5684
minLines={1}

src/components/workspace/__tests__/Repl.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ const mockErrorOutput: ErrorOutput = {
3535

3636
test('Repl renders correctly', () => {
3737
const props = {
38-
output: [mockResultOutput, mockCodeOutput, mockErrorOutput, mockRunningOutput],
39-
replValue: '',
38+
handleBrowseHistoryDown: () => {},
39+
handleBrowseHistoryUp: () => {},
4040
handleReplValueChange: (newCode: string) => {},
4141
handleReplEval: () => {},
42-
handleReplOutputClear: () => {}
42+
handleReplOutputClear: () => {},
43+
output: [mockResultOutput, mockCodeOutput, mockErrorOutput, mockRunningOutput],
44+
replValue: ''
4345
}
4446
const app = <Repl {...props} />
4547
const tree = shallow(app)

0 commit comments

Comments
 (0)