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
1 change: 1 addition & 0 deletions src/actions/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const END_CLEAR_CONTEXT = 'END_CLEAR_CONTEXT';
export const ENSURE_LIBRARIES_LOADED = 'ENSURE_LIBRARIES_LOADED';
export const EVAL_EDITOR = 'EVAL_EDITOR';
export const EVAL_REPL = 'EVAL_REPL';
export const PROMPT_AUTOCOMPLETE = 'PROMPT_AUTOCOMPLETE';
// For interpreting code blocks silently (e.g. prepend) BEFORE the test case is run
export const EVAL_SILENT = 'EVAL_SILENT';
export const EVAL_TESTCASE = 'EVAL_TESTCASE';
Expand Down
13 changes: 13 additions & 0 deletions src/actions/workspaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,16 @@ export const updateHasUnsavedChanges = (
workspaceLocation,
hasUnsavedChanges
});

export const promptAutocomplete = (
workspaceLocation: WorkspaceLocation,
row: number,
column: number,
callback: any // TODO: define a type for this
) =>
action(actionTypes.PROMPT_AUTOCOMPLETE, {
workspaceLocation,
row,
column,
callback
});
2 changes: 2 additions & 0 deletions src/components/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export interface IDispatchProps {
handleDebuggerResume: () => void;
handleDebuggerReset: () => void;
handleToggleEditorAutorun: () => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
}

type PlaygroundState = {
Expand Down Expand Up @@ -272,6 +273,7 @@ class Playground extends React.Component<IPlaygroundProps, PlaygroundState> {
handleDeclarationNavigate: this.props.handleDeclarationNavigate,
handleEditorEval: this.props.handleEditorEval,
handleEditorValueChange: this.props.handleEditorValueChange,
handlePromptAutocomplete: this.props.handlePromptAutocomplete,
handleFinishInvite: this.props.handleFinishInvite,
sharedbAceInitValue: this.props.sharedbAceInitValue,
sharedbAceIsInviting: this.props.sharedbAceIsInviting,
Expand Down
3 changes: 2 additions & 1 deletion src/components/__tests__/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ const baseProps = {
handleUsingSubst: (usingSubst: boolean) => {},
handleDebuggerPause: () => {},
handleDebuggerResume: () => {},
handleDebuggerReset: () => {}
handleDebuggerReset: () => {},
handlePromptAutocomplete: (row: number, col: number, callback: any) => {}
};

const testValueProps: IPlaygroundProps = {
Expand Down
2 changes: 2 additions & 0 deletions src/components/academy/grading/GradingWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export type DispatchProps = {
handleDebuggerReset: () => void;
handleUpdateCurrentSubmissionId: (submissionId: number, questionId: number) => void;
handleUpdateHasUnsavedChanges: (hasUnsavedChanges: boolean) => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
};

class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
Expand Down Expand Up @@ -179,6 +180,7 @@ class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
highlightedLines: this.props.highlightedLines,
newCursorPosition: this.props.newCursorPosition,
handleEditorUpdateBreakpoints: this.props.handleEditorUpdateBreakpoints,
handlePromptAutocomplete: this.props.handlePromptAutocomplete,
isEditorAutorun: false
}
: undefined,
Expand Down
2 changes: 2 additions & 0 deletions src/components/assessment/AssessmentWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export type DispatchProps = {
handleDebuggerPause: () => void;
handleDebuggerResume: () => void;
handleDebuggerReset: () => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
};

class AssessmentWorkspace extends React.Component<
Expand Down Expand Up @@ -248,6 +249,7 @@ class AssessmentWorkspace extends React.Component<
highlightedLines: this.props.highlightedLines,
newCursorPosition: this.props.newCursorPosition,
handleEditorUpdateBreakpoints: this.props.handleEditorUpdateBreakpoints,
handlePromptAutocomplete: this.props.handlePromptAutocomplete,
isEditorAutorun: false
}
: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const defaultProps: AssessmentWorkspaceProps = {
handleDebuggerPause: () => {},
handleDebuggerResume: () => {},
handleDebuggerReset: () => {},
handlePromptAutocomplete: (row: number, col: number, callback: any) => {},
isRunning: false,
isDebugging: false,
enableDebugging: false,
Expand Down
2 changes: 2 additions & 0 deletions src/components/missionControl/EditingWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type DispatchProps = {
handleDebuggerReset: () => void;
handleUpdateCurrentAssessmentId: (assessmentId: number, questionId: number) => void;
handleUpdateHasUnsavedChanges: (hasUnsavedChanges: boolean) => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
};

interface IState {
Expand Down Expand Up @@ -182,6 +183,7 @@ class AssessmentWorkspace extends React.Component<AssessmentWorkspaceProps, ISta
newCursorPosition: this.props.newCursorPosition,
handleEditorUpdateBreakpoints: this.props.handleEditorUpdateBreakpoints,
handleUpdateHasUnsavedChanges: this.props.handleUpdateHasUnsavedChanges,
handlePromptAutocomplete: this.props.handlePromptAutocomplete,
isEditorAutorun: false
}
: undefined,
Expand Down
2 changes: 2 additions & 0 deletions src/components/sourcecast/Sourcecast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export interface IDispatchProps {
handleEditorEval: () => void;
handleEditorHeightChange: (height: number) => void;
handleEditorValueChange: (val: string) => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
handleEditorWidthChange: (widthChange: number) => void;
handleEditorUpdateBreakpoints: (breakpoints: string[]) => void;
handleExternalSelect: (externalLibraryName: ExternalLibraryName) => void;
Expand Down Expand Up @@ -234,6 +235,7 @@ class Sourcecast extends React.Component<ISourcecastProps> {
};
const sourcecastControlbarProps: ISourcecastControlbarProps = {
handleEditorValueChange: this.props.handleEditorValueChange,
handlePromptAutocomplete: this.props.handlePromptAutocomplete,
handleSetCodeDeltasToApply: this.props.handleSetCodeDeltasToApply,
handleSetEditorReadonly: this.props.handleSetEditorReadonly,
handleSetInputToApply: this.props.handleSetInputToApply,
Expand Down
1 change: 1 addition & 0 deletions src/components/sourcecast/SourcecastControlbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export interface ISourcecastControlbarProps {
playbackStatus: PlaybackStatus;
handleChapterSelect: (chapter: number) => void;
handleExternalSelect: (name: ExternalLibraryName) => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
}

export interface ISourcecastControlbarState {
Expand Down
22 changes: 22 additions & 0 deletions src/components/workspace/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import AceEditor, { IAnnotation } from 'react-ace';
import { HotKeys } from 'react-hotkeys';
import sharedbAce from 'sharedb-ace';

import { require as acequire } from 'ace-builds';
import 'ace-builds/src-noconflict/ext-language_tools';
import 'ace-builds/src-noconflict/ext-searchbox';
import { createContext, getAllOccurrencesInScope } from 'js-slang';
Expand Down Expand Up @@ -35,6 +36,7 @@ export interface IEditorProps {
handleEditorValueChange: (newCode: string) => void;
handleEditorUpdateBreakpoints: (breakpoints: string[]) => void;
handleFinishInvite?: () => void;
handlePromptAutocomplete: (row: number, col: number, callback: any) => void;
handleSetWebsocketStatus?: (websocketStatus: number) => void;
handleUpdateHasUnsavedChanges?: (hasUnsavedChanges: boolean) => void;
}
Expand All @@ -43,13 +45,21 @@ export interface IPosition {
row: number;
column: number;
}
export interface IAutocompletionResult {
caption: string;
value: string;
meta?: string;
docHTML?: string;
score?: number;
}

class Editor extends React.PureComponent<IEditorProps, {}> {
public ShareAce: any;
public AceEditor: React.RefObject<AceEditor>;
private markerIds: number[];
private onChangeMethod: (newCode: string) => void;
private onValidateMethod: (annotations: IAnnotation[]) => void;
private completer: {};

constructor(props: IEditorProps) {
super(props);
Expand All @@ -68,6 +78,13 @@ class Editor extends React.PureComponent<IEditorProps, {}> {
this.props.handleEditorEval();
}
};

this.completer = {
getCompletions: (editor: any, session: any, pos: any, prefix: any, callback: any) => {
// console.log(pos); // Cursor col is insertion location i.e. last char col + 1
this.props.handlePromptAutocomplete(pos.row, pos.column, callback);
}
};
}

public getBreakpoints() {
Expand Down Expand Up @@ -117,6 +134,9 @@ class Editor extends React.PureComponent<IEditorProps, {}> {
// Change all info annotations to error annotations
session.on('changeAnnotation', this.handleAnnotationChange(session));

// Start autocompletion
acequire('ace/ext/language_tools').setCompleters([this.completer]);

// Has session ID
if (this.props.editorSessionId !== '') {
this.handleStartCollabEditing(editor);
Expand Down Expand Up @@ -214,6 +234,8 @@ class Editor extends React.PureComponent<IEditorProps, {}> {
value={this.props.editorValue}
width="100%"
setOptions={{
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
fontFamily: "'Inconsolata', 'Consolas', monospace"
}}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/components/workspace/__tests__/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ test('Editor renders correctly', () => {
handleEditorUpdateBreakpoints: breakpoints => {},
handleFinishInvite: () => {},
handleSetWebsocketStatus: websocketStatus => {},
handleUpdateHasUnsavedChanges: hasUnsavedChanges => {}
handleUpdateHasUnsavedChanges: hasUnsavedChanges => {},
handlePromptAutocomplete: (row: number, col: number, callback: any) => {}
};
const app = <Editor {...props} />;
const tree = shallow(app);
Expand Down
3 changes: 3 additions & 0 deletions src/containers/ApplicationContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
changeExecTime,
ensureLibrariesLoaded,
externalLibrarySelect,
promptAutocomplete,
WorkspaceLocations
} from '../actions/workspaces';
import Application, { IDispatchProps, IStateProps } from '../components/Application';
Expand Down Expand Up @@ -47,6 +48,8 @@ const mapDispatchToProps: MapDispatchToProps<IDispatchProps, {}> = (dispatch: Di
workspaceLocation
),
handleEditorValueChange: (val: string) => updateEditorValue(val, workspaceLocation),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(workspaceLocation, row, col, callback),
handleEditorUpdateBreakpoints: (breakpoints: string[]) =>
setEditorBreakpoint(breakpoints, workspaceLocation),
handleEnsureLibrariesLoaded: ensureLibrariesLoaded,
Expand Down
5 changes: 4 additions & 1 deletion src/containers/PlaygroundContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
initInvite,
invalidEditorSessionId,
navigateToDeclaration,
promptAutocomplete,
setEditorBreakpoint,
setEditorSessionId,
setWebsocketStatus,
Expand Down Expand Up @@ -104,7 +105,9 @@ const mapDispatchToProps: MapDispatchToProps<IDispatchProps, {}> = (dispatch: Di
handleUsingSubst: (usingSubst: boolean) => toggleUsingSubst(usingSubst),
handleDebuggerPause: () => beginDebuggerPause(workspaceLocation),
handleDebuggerResume: () => debuggerResume(workspaceLocation),
handleDebuggerReset: () => debuggerReset(workspaceLocation)
handleDebuggerReset: () => debuggerReset(workspaceLocation),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(workspaceLocation, row, col, callback)
},
dispatch
);
Expand Down
5 changes: 4 additions & 1 deletion src/containers/academy/grading/GradingWorkspaceContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
evalTestcase,
fetchGrading,
navigateToDeclaration,
promptAutocomplete,
setEditorBreakpoint,
updateActiveTab,
updateEditorValue,
Expand Down Expand Up @@ -101,7 +102,9 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dis
updateHasUnsavedChanges(workspaceLocation, unsavedChanges),
handleDebuggerPause: () => beginDebuggerPause(workspaceLocation),
handleDebuggerResume: () => debuggerResume(workspaceLocation),
handleDebuggerReset: () => debuggerReset(workspaceLocation)
handleDebuggerReset: () => debuggerReset(workspaceLocation),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(workspaceLocation, row, col, callback)
},
dispatch
);
Expand Down
5 changes: 4 additions & 1 deletion src/containers/assessment/AssessmentWorkspaceContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
evalTestcase,
fetchAssessment,
navigateToDeclaration,
promptAutocomplete,
setEditorBreakpoint,
submitAnswer,
updateActiveTab,
Expand Down Expand Up @@ -102,7 +103,9 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dis
handleUpdateCurrentAssessmentId: updateCurrentAssessmentId,
handleDebuggerPause: () => beginDebuggerPause(workspaceLocation),
handleDebuggerResume: () => debuggerResume(workspaceLocation),
handleDebuggerReset: () => debuggerReset(workspaceLocation)
handleDebuggerReset: () => debuggerReset(workspaceLocation),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(workspaceLocation, row, col, callback)
},
dispatch
);
Expand Down
5 changes: 4 additions & 1 deletion src/containers/missionControl/EditingWorkspaceContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
evalRepl,
evalTestcase,
navigateToDeclaration,
promptAutocomplete,
setEditorBreakpoint,
submitAnswer,
updateEditorValue,
Expand Down Expand Up @@ -95,7 +96,9 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dis
handleUpdateCurrentAssessmentId: updateCurrentAssessmentId,
handleDebuggerPause: () => beginDebuggerPause(workspaceLocation),
handleDebuggerResume: () => debuggerResume(workspaceLocation),
handleDebuggerReset: () => debuggerReset(workspaceLocation)
handleDebuggerReset: () => debuggerReset(workspaceLocation),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(workspaceLocation, row, col, callback)
},
dispatch
);
Expand Down
5 changes: 4 additions & 1 deletion src/containers/sourcecast/SourcecastContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
externalLibrarySelect,
fetchSourcecastIndex,
navigateToDeclaration,
promptAutocomplete,
setCodeDeltasToApply,
setEditorBreakpoint,
setEditorReadonly,
Expand Down Expand Up @@ -112,7 +113,9 @@ const mapDispatchToProps: MapDispatchToProps<IDispatchProps, {}> = (dispatch: Di
handleToggleEditorAutorun: () => toggleEditorAutorun(location),
handleDebuggerPause: () => beginDebuggerPause(location),
handleDebuggerResume: () => debuggerResume(location),
handleDebuggerReset: () => debuggerReset(location)
handleDebuggerReset: () => debuggerReset(location),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(location, row, col, callback)
},
dispatch
);
Expand Down
5 changes: 4 additions & 1 deletion src/containers/sourcecast/SourcereelContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
externalLibrarySelect,
fetchSourcecastIndex,
navigateToDeclaration,
promptAutocomplete,
recordInit,
recordInput,
saveSourcecastData,
Expand Down Expand Up @@ -108,7 +109,9 @@ const mapDispatchToProps: MapDispatchToProps<IDispatchProps, {}> = (dispatch: Di
handleToggleEditorAutorun: () => toggleEditorAutorun(location),
handleDebuggerPause: () => beginDebuggerPause(location),
handleDebuggerResume: () => debuggerResume(location),
handleDebuggerReset: () => debuggerReset(location)
handleDebuggerReset: () => debuggerReset(location),
handlePromptAutocomplete: (row: number, col: number, callback: any) =>
promptAutocomplete(location, row, col, callback)
},
dispatch
);
Expand Down
55 changes: 55 additions & 0 deletions src/reducers/documentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { SourceDocumentation } from 'js-slang';
import { externalLibraries } from './externalLibraries';

const externalLibrariesDocumentation = {};

const MAX_CAPTION_LENGTH = 25;

function shortenCaption(name: string): string {
if (name.length <= MAX_CAPTION_LENGTH) {
return name;
}

return (name = name.substring(0, MAX_CAPTION_LENGTH - 3) + '...');
}

for (const [lib, names] of externalLibraries) {
const libDocs = names.map((name: string) => {
if (name in SourceDocumentation.ext_lib) {
return {
caption: shortenCaption(name),
value: name,
meta: SourceDocumentation.ext_lib[name].meta,
docHTML: SourceDocumentation.ext_lib[name].description
};
} else {
return {
caption: shortenCaption(name),
value: name,
meta: 'const'
};
}
});

externalLibrariesDocumentation[lib] = libDocs;
}

const builtinDocumentation = {};

Object.entries(SourceDocumentation.builtins).forEach((chapterDoc: any) => {
const [chapter, docs] = chapterDoc;
builtinDocumentation[chapter] = Object.entries(docs).map((entry: any) => {
const [name, info] = entry;
return {
caption: shortenCaption(name),
value: name,
meta: info.meta,
docHTML: info.description
};
});
});

export const Documentation = {
builtins: builtinDocumentation,
externalLibraries: externalLibrariesDocumentation
};
Loading