From 06a4d2900d6e040aa1633d260056e86343cd7b3b Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 23 Jun 2019 20:50:49 -0700 Subject: [PATCH] separate vscode from services --- src/editor/commands/index.ts | 21 ++++++++++-- src/editor/commands/loadSolution.ts | 4 +-- src/editor/index.ts | 2 +- src/extension.ts | 6 +++- src/services/git/index.ts | 5 ++- src/services/testResult.ts | 53 ----------------------------- src/services/tutorialSetup.ts | 27 --------------- src/state/actions/index.ts | 21 ++++++------ src/state/index.ts | 14 +++++--- src/state/machine.ts | 6 ++-- typings/index.d.ts | 2 ++ 11 files changed, 53 insertions(+), 108 deletions(-) delete mode 100644 src/services/testResult.ts delete mode 100644 src/services/tutorialSetup.ts diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index c8f0067b..5e9b784d 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -16,6 +16,9 @@ const COMMANDS = { RECEIVE_ACTION: 'coderoad.receive_action', OPEN_FILE: 'coderoad.open_file', RUN_TEST: 'coderoad.run_test', + TEST_PASS: 'coderoad.test_pass', + TEST_FAIL: 'coderoad.test_fail', + SET_LAYOUT: 'coderoad.set_layout', } interface CreateCommandProps { @@ -41,8 +44,12 @@ export const createCommands = ({ context, machine, storage, git, position }: Cre machine.activate() }, // open React webview - [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.One) => { + [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { + // setup 1x1 horizontal layout + vscode.commands.executeCommand('vscode.setEditorLayout', { orientation: 0, groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }] }) webview.createOrShow(column); + // NOTE: createOrShow and layout command cannot be async + // this creates an async issue where the webview cannot detect when it has been initialized setTimeout(() => { machine.send('WEBVIEW_INITIALIZED') }, 2000) @@ -112,5 +119,15 @@ export const createCommands = ({ context, machine, storage, git, position }: Cre onSuccess: () => machine.send('TEST_PASS'), onFail: () => machine.send('TEST_FAIL') }) - } + }, + [COMMANDS.TEST_PASS]: () => { + vscode.window.showInformationMessage('PASS') + }, + [COMMANDS.TEST_FAIL]: () => { + vscode.window.showWarningMessage('FAIL') + }, + [COMMANDS.SET_LAYOUT]: () => { + console.log('setLayout') + vscode.commands.executeCommand('vscode.setEditorLayout', { orientation: 0, groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }] }) + }, }) \ No newline at end of file diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts index 22d41257..02ef752e 100644 --- a/src/editor/commands/loadSolution.ts +++ b/src/editor/commands/loadSolution.ts @@ -2,7 +2,7 @@ import * as CR from 'typings' import * as storage from '../../services/storage' import { gitLoadCommits, gitClear } from '../../services/git' -export default async function loadSolution(): Promise { +export default async function loadSolution(dispatch: CR.EditorDispatch): Promise { const [position, tutorial]: [CR.Position, CR.Tutorial | undefined] = await Promise.all([ storage.getPosition(), storage.getTutorial(), @@ -17,5 +17,5 @@ export default async function loadSolution(): Promise { const { solution } = tutorial.data.steps[position.stepId].actions await gitClear() - await gitLoadCommits(solution) + await gitLoadCommits(solution, dispatch) } diff --git a/src/editor/index.ts b/src/editor/index.ts index 57f97bca..e98fa372 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -61,7 +61,7 @@ class Editor { } // execute vscode command - public dispatch = (type: string, payload: any) => { + public dispatch = (type: string, payload?: any) => { vscode.commands.executeCommand(type, payload) } } diff --git a/src/extension.ts b/src/extension.ts index ad32b1d8..c8e2128b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,10 +1,11 @@ +import * as vscode from 'vscode' import { setWorkspaceRoot } from './services/node' import StateMachine from './state' import Editor from './editor' // state machine that governs application logic -export const machine = new StateMachine() +export const machine = new StateMachine({ dispatch: vscode.commands.executeCommand }) // vscode editor export const editor = new Editor({ @@ -12,5 +13,8 @@ export const editor = new Editor({ setWorkspaceRoot, }) +// activate run on vscode extension initialization export const activate = editor.activate + +// deactive run on vscode extension shut down export const deactivate = editor.deactivate diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 4cd7e34a..c3e777cc 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -1,4 +1,3 @@ -import * as vscode from 'vscode' import * as CR from 'typings' import { exec, exists } from '../node' @@ -9,7 +8,7 @@ const gitOrigin = 'coderoad' MULTIPLE git cherry-pick %COMMIT_START%..%COMMIT_END% if shell, run shell */ -export async function gitLoadCommits(actions: CR.TutorialAction): Promise { +export async function gitLoadCommits(actions: CR.TutorialAction, dispatch: CR.EditorDispatch): Promise { const { commits, commands, files } = actions console.log('commits to load', commits) @@ -41,7 +40,7 @@ export async function gitLoadCommits(actions: CR.TutorialAction): Promise if (files) { for (const filePath of files) { - vscode.commands.executeCommand('coderoad.open_file', filePath) + dispatch('coderoad.open_file', filePath) } } } diff --git a/src/services/testResult.ts b/src/services/testResult.ts deleted file mode 100644 index 470fe50e..00000000 --- a/src/services/testResult.ts +++ /dev/null @@ -1,53 +0,0 @@ -// import * as CR from 'typings' -// import * as vscode from 'vscode' -// import * as storage from './storage' - -// export async function onSuccess(position: CR.Position) { -// console.log('onSuccess', position) -// vscode.window.showInformationMessage('SUCCESS') - -// // calculate progress changes -// const [progress, tutorial] = await Promise.all([storage.getProgress(), storage.getTutorial()]) - -// if (!tutorial) { -// throw new Error('No tutorial found') -// } - -// if (!position.stepId) { -// throw new Error('No step position found') -// } - -// const { data } = tutorial - -// // step complete -// const nextProgress = progress -// nextProgress.steps[position.stepId] = true - -// // is stage complete -// const steps = data.stages[position.stageId].stepList -// const isStageComplete = progress.stages[position.stageId] || steps[steps.length - 1] === position.stepId -// nextProgress.stages[position.stageId] = isStageComplete - -// // is level complete -// if (isStageComplete) { -// const stages = data.levels[position.levelId].stageList -// const isLevelComplete = progress.levels[position.levelId] || stages[stages.length - 1] === position.stageId -// nextProgress.levels[position.levelId] = isLevelComplete - -// if (isLevelComplete) { -// const levels = data.summary.levelList -// const isTutorialComplete = progress.complete || levels[levels.length - 1] === position.levelId -// nextProgress.complete = isTutorialComplete -// } -// } -// console.log('nextProgress', nextProgress) - -// // update ls progress -// storage.updateProgress(nextProgress) -// // send({ type: 'STEP_COMPLETE', payload: { progress: nextProgress } }) -// } - -// export async function onFailure() { -// // TODO: capture analytics on stepId -// vscode.window.showWarningMessage('FAIL') -// } diff --git a/src/services/tutorialSetup.ts b/src/services/tutorialSetup.ts deleted file mode 100644 index 140604d7..00000000 --- a/src/services/tutorialSetup.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as CR from 'typings' -import * as position from '../services/position' -import * as storage from '../services/storage' -import { isEmptyWorkspace } from '../editor/workspace' -import { gitLoadCommits, gitInitIfNotExists, gitSetupRemote } from '../services/git' - -const testRepo = 'https://github.com/ShMcK/coderoad-tutorial-basic.git' - -async function initializeTutorial(tutorial: CR.Tutorial): Promise { - // TODO: refactor to allow client to call initialization - const pos: CR.Position = await position.getInitial(tutorial) - - // eslint-disable-next-line - const { steps } = tutorial.data - const { setup } = steps[pos.stepId].actions - await gitLoadCommits(setup) -} - -export default async function tutorialSetup(tutorial: CR.Tutorial): Promise { - await isEmptyWorkspace() - - await gitInitIfNotExists() - - await Promise.all([gitSetupRemote(testRepo), storage.setTutorial(tutorial), storage.resetProgress()]) - - await initializeTutorial(tutorial) -} diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 7e5784cc..38f5aa32 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -3,7 +3,6 @@ import { assign } from 'xstate' import { machine } from '../../extension' import api from '../../services/api' import * as CR from 'typings' -import * as vscode from 'vscode' import * as storage from '../../services/storage' import * as git from '../../services/git' @@ -15,10 +14,10 @@ let currentProgress: CR.Progress = { complete: false, } -export default { +export default (dispatch: CR.EditorDispatch) => ({ createWebview() { console.log('execute coderoad.open_webview') - vscode.commands.executeCommand('coderoad.open_webview') + dispatch('coderoad.open_webview') }, async newOrContinue() { // verify that the user has a tutorial & progress @@ -45,11 +44,11 @@ export default { currentTutorial = tutorial console.log('api') console.log(tutorial) - vscode.commands.executeCommand('coderoad.tutorial_launch', tutorial) + dispatch('coderoad.tutorial_launch', tutorial) }, tutorialSetup() { - vscode.commands.executeCommand('coderoad.tutorial_setup', currentTutorial) - vscode.commands.executeCommand('coderoad.open_webview', vscode.ViewColumn.Two) + dispatch('coderoad.tutorial_setup', currentTutorial) + dispatch('coderoad.open_webview', 2) }, initializeNewTutorial: assign({ position: (context: any): CR.Position => { @@ -104,13 +103,13 @@ export default { } }), testStart() { - vscode.commands.executeCommand('coderoad.run_test') + dispatch('coderoad.run_test') }, testPass() { - vscode.window.showInformationMessage('PASS') + dispatch('coderoad.test_pass') }, testFail() { - vscode.window.showWarningMessage('FAIL') + dispatch('coderoad.test_fail') }, // @ts-ignore progressUpdate: assign({ @@ -166,6 +165,6 @@ export default { stepLoadCommits(context: CR.MachineContext): void { const { data, position } = context const { setup } = data.steps[position.stepId].actions - git.gitLoadCommits(setup) + git.gitLoadCommits(setup, dispatch) } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/state/index.ts b/src/state/index.ts index 1dc28042..f7111418 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,11 +1,14 @@ import { interpret, Interpreter } from 'xstate' import * as CR from 'typings' -import machine from './machine' -import * as vscode from 'vscode' +import createMachine from './machine' // machine interpreter // https://xstate.js.org/docs/guides/interpretation.html +interface Props { + dispatch: CR.EditorDispatch +} + class StateMachine { private machineOptions = { logger: console.log, @@ -14,7 +17,8 @@ class StateMachine { execute: true } private service: Interpreter - constructor() { + constructor({ dispatch }: Props) { + const machine = createMachine(dispatch) this.service = interpret(machine, this.machineOptions) // logging .onTransition(state => { @@ -22,9 +26,9 @@ class StateMachine { if (state.changed) { console.log('next state') console.log(state.value) - vscode.commands.executeCommand('coderoad.send_state', { state: state.value, data: state.context }) + dispatch('coderoad.send_state', { state: state.value, data: state.context }) } else { - vscode.commands.executeCommand('coderoad.send_data', { data: state.context }) + dispatch('coderoad.send_data', { data: state.context }) } }) } diff --git a/src/state/machine.ts b/src/state/machine.ts index bf3b169d..201d05be 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -1,11 +1,11 @@ import { Machine } from 'xstate' import * as CR from 'typings' -import actions from './actions' +import createActions from './actions' import guards from './guards' import initialContext from './context' -export const machine = Machine< +export const machine = (dispatch: CR.EditorDispatch) => Machine< CR.MachineContext, CR.MachineStateSchema, CR.MachineEvent @@ -164,7 +164,7 @@ export const machine = Machine< } }, { - actions, + actions: createActions(dispatch), guards, activities: {}, }, diff --git a/typings/index.d.ts b/typings/index.d.ts index 6100d36b..43f83e50 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -172,3 +172,5 @@ export interface StateMachine { deactivate(): void send(action: string | Action): void } + +export type EditorDispatch = (type: string, payload?: any) => void \ No newline at end of file