Skip to content

Commit 9f23466

Browse files
authored
Merge pull request #19 from ShMcK/fix/issues
Fix/issues
2 parents 3a2c087 + df9de6e commit 9f23466

File tree

11 files changed

+174
-138
lines changed

11 files changed

+174
-138
lines changed

src/editor/ReactWebView.ts

+7-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class ReactWebView {
2424

2525
// Listen for when the panel is disposed
2626
// This happens when the user closes the panel or when the panel is closed programatically
27-
this.panel.onDidDispose(() => this.dispose(), null, this.disposables)
27+
this.panel.onDidDispose(this.dispose, this, this.disposables)
2828

2929
// Handle messages from the webview
3030
const onReceive = (action: string | CR.Action) => {
@@ -75,6 +75,7 @@ class ReactWebView {
7575
// unfortunately there is no easy way of doing this
7676
const webPanelListener = setInterval(() => {
7777
if (this.loaded) {
78+
// callback tells editor the webview has loaded
7879
setTimeout(callback)
7980
clearInterval(webPanelListener)
8081
}
@@ -91,16 +92,11 @@ class ReactWebView {
9192
}
9293
}
9394

94-
public dispose(): void {
95+
private async dispose(): Promise<void> {
9596
// Clean up our resources
97+
this.loaded = false
9698
this.panel.dispose()
97-
98-
while (this.disposables.length) {
99-
const x = this.disposables.pop()
100-
if (x) {
101-
x.dispose()
102-
}
103-
}
99+
Promise.all(this.disposables.map((x) => x.dispose()))
104100
}
105101

106102
private createWebviewPanel(column: number): vscode.WebviewPanel {
@@ -153,14 +149,15 @@ class ReactWebView {
153149
<meta name='theme-color' content='#000000'>
154150
<title>React App</title>
155151
<link rel='manifest' href='./manifest.json' />
152+
156153
<!-- TODO: load styles through package -->
157154
<link rel='stylesheet' href='https://unpkg.com/@alifd/next/dist/next.css' />
158155
<link rel='stylesheet' type='text/css' href='${styleUri}'>
156+
159157
<meta http-equiv='Content-Security-Policy' content="font-src *; img-src vscode-resource: https:; script-src 'nonce-${n1}' 'nonce-${n2}' 'nonce-${n3}'; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
160158
<base href='${vscode.Uri.file(path.join(this.extensionPath, 'build')).with({
161159
scheme: 'vscode-resource',
162160
})}/'>
163-
<style></style>
164161
</head>
165162
166163
<body>

src/editor/commands/index.ts

+117-99
Original file line numberDiff line numberDiff line change
@@ -29,110 +29,128 @@ interface CreateCommandProps {
2929
position: any
3030
}
3131

32-
// React panel webview
33-
let webview: any
32+
export const createCommands = ({ context, machine, storage, git, position }: CreateCommandProps) => {
33+
// React panel webview
34+
let webview: any
3435

35-
export const createCommands = ({ context, machine, storage, git, position }: CreateCommandProps) => ({
36-
// initialize
37-
[COMMANDS.START]: () => {
38-
if (webview) {
39-
console.log('CodeRoad already loaded')
40-
return
41-
}
42-
// set local storage workspace
43-
setStorage(context.workspaceState)
36+
return {
37+
// initialize
38+
[COMMANDS.START]: () => {
39+
let webviewState: 'INITIALIZING' | 'RESTARTING'
40+
if (!webview) {
41+
webviewState = 'INITIALIZING'
42+
} else if (webview.loaded) {
43+
// already loaded
44+
vscode.window.showInformationMessage('CodeRoad already open')
45+
return
46+
} else {
47+
webviewState = 'RESTARTING'
48+
}
49+
50+
setStorage(context.workspaceState)
4451

45-
// activate machine
46-
webview = new ReactWebView(context.extensionPath)
47-
machine.activate()
48-
},
49-
// open React webview
50-
[COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => {
51-
// setup 1x1 horizontal layout
52-
vscode.commands.executeCommand('vscode.setEditorLayout', {
53-
orientation: 0,
54-
groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }],
55-
})
56-
const callback = () => machine.send('WEBVIEW_INITIALIZED')
57-
webview.createOrShow(column, callback)
58-
},
59-
// launch a new tutorial
60-
// NOTE: may be better to move into action as logic is primarily non-vscode
61-
[COMMANDS.TUTORIAL_LAUNCH]: async (tutorial: CR.Tutorial) => {
62-
console.log('launch tutorial')
52+
// activate machine
53+
webview = new ReactWebView(context.extensionPath)
54+
if (webviewState === 'INITIALIZING') {
55+
machine.activate()
56+
} else if (webviewState === 'RESTARTING') {
57+
setTimeout(() => {
58+
// timeout hack to make data update on new windows
59+
// @ts-ignore
60+
machine.refresh()
61+
}, 1000)
62+
}
63+
},
64+
// open React webview
65+
[COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => {
66+
// setup 1x1 horizontal layout
67+
vscode.commands.executeCommand('vscode.setEditorLayout', {
68+
orientation: 0,
69+
groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }],
70+
})
71+
const callback = () => {
72+
machine.send('WEBVIEW_INITIALIZED')
73+
}
74+
webview.createOrShow(column, callback)
75+
},
76+
// launch a new tutorial
77+
// NOTE: may be better to move into action as logic is primarily non-vscode
78+
[COMMANDS.TUTORIAL_LAUNCH]: async ({ tutorial, dispatch }: any) => {
79+
console.log('launch tutorial')
6380

64-
await isEmptyWorkspace()
81+
await isEmptyWorkspace()
6582

66-
await git.gitInitIfNotExists()
83+
await git.gitInitIfNotExists()
6784

68-
// TODO: use actual tutorial repo
69-
await Promise.all([git.gitSetupRemote(tutorial.meta.repo), storage.setTutorial(tutorial), storage.resetProgress()])
85+
// TODO: use actual tutorial repo
86+
await Promise.all([git.gitSetupRemote(tutorial.meta.repo), storage.setTutorial(tutorial), storage.resetProgress()])
7087

71-
// TODO: refactor to allow client to call initialization
72-
const pos: CR.Position = await position.getInitial(tutorial)
88+
// TODO: refactor to allow client to call initialization
89+
const pos: CR.Position = await position.getInitial(tutorial)
7390

74-
// eslint-disable-next-line
75-
const { steps } = tutorial.data
76-
const { setup } = steps[pos.stepId].actions
77-
await git.gitLoadCommits(setup)
78-
machine.send('TUTORIAL_LOADED')
79-
},
80-
[COMMANDS.TUTORIAL_SETUP]: async (tutorial: CR.Tutorial) => {
81-
console.log('tutorial setup', tutorial)
82-
// setup onSave hook
83-
const languageIds = tutorial.meta.languages
84-
console.log(`languageIds: ${languageIds.join(', ')}`)
85-
vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => {
86-
console.log('save document', document)
87-
if (languageIds.includes(document.languageId) && document.uri.scheme === 'file') {
88-
// do work
89-
machine.send('TEST_RUN')
90-
}
91-
})
92-
},
93-
// open a file
94-
[COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => {
95-
console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`)
96-
try {
97-
const workspaceRoot = vscode.workspace.rootPath
98-
if (!workspaceRoot) {
99-
throw new Error('No workspace root path')
91+
// eslint-disable-next-line
92+
const { steps } = tutorial.data
93+
const { setup } = steps[pos.stepId].actions
94+
await git.gitLoadCommits(setup, dispatch)
95+
machine.send('TUTORIAL_LOADED')
96+
},
97+
[COMMANDS.TUTORIAL_SETUP]: async (tutorial: CR.Tutorial) => {
98+
console.log('tutorial setup', tutorial)
99+
// setup onSave hook
100+
const languageIds = tutorial.meta.languages
101+
console.log(`languageIds: ${languageIds.join(', ')}`)
102+
vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => {
103+
console.log('save document', document)
104+
if (languageIds.includes(document.languageId) && document.uri.scheme === 'file') {
105+
// do work
106+
machine.send('TEST_RUN')
107+
}
108+
})
109+
},
110+
// open a file
111+
[COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => {
112+
console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`)
113+
try {
114+
const workspaceRoot = vscode.workspace.rootPath
115+
if (!workspaceRoot) {
116+
throw new Error('No workspace root path')
117+
}
118+
const absoluteFilePath = join(workspaceRoot, relativeFilePath)
119+
const doc = await vscode.workspace.openTextDocument(absoluteFilePath)
120+
await vscode.window.showTextDocument(doc, vscode.ViewColumn.One)
121+
} catch (error) {
122+
console.log(`Failed to open file ${relativeFilePath}`, error)
100123
}
101-
const absoluteFilePath = join(workspaceRoot, relativeFilePath)
102-
const doc = await vscode.workspace.openTextDocument(absoluteFilePath)
103-
await vscode.window.showTextDocument(doc, vscode.ViewColumn.One)
104-
} catch (error) {
105-
console.log(`Failed to open file ${relativeFilePath}`, error)
106-
}
107-
},
108-
// send messages to webview
109-
[COMMANDS.SEND_STATE]: (payload: { data: any; state: any }) => {
110-
webview.postMessage({ type: 'SET_STATE', payload })
111-
},
112-
[COMMANDS.SEND_DATA]: (payload: { data: any }) => {
113-
webview.postMessage({ type: 'SET_DATA', payload })
114-
},
115-
[COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => {
116-
// send received actions from web-app into state machine
117-
machine.send(action)
118-
},
119-
[COMMANDS.RUN_TEST]: () => {
120-
runTest({
121-
onSuccess: () => machine.send('TEST_PASS'),
122-
onFail: () => machine.send('TEST_FAIL'),
123-
})
124-
},
125-
[COMMANDS.TEST_PASS]: () => {
126-
vscode.window.showInformationMessage('PASS')
127-
},
128-
[COMMANDS.TEST_FAIL]: () => {
129-
vscode.window.showWarningMessage('FAIL')
130-
},
131-
[COMMANDS.SET_LAYOUT]: () => {
132-
console.log('setLayout')
133-
vscode.commands.executeCommand('vscode.setEditorLayout', {
134-
orientation: 0,
135-
groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }],
136-
})
137-
},
138-
})
124+
},
125+
// send messages to webview
126+
[COMMANDS.SEND_STATE]: (payload: { data: any; state: any }) => {
127+
webview.postMessage({ type: 'SET_STATE', payload })
128+
},
129+
[COMMANDS.SEND_DATA]: (payload: { data: any }) => {
130+
webview.postMessage({ type: 'SET_DATA', payload })
131+
},
132+
[COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => {
133+
// send received actions from web-app into state machine
134+
machine.send(action)
135+
},
136+
[COMMANDS.RUN_TEST]: () => {
137+
runTest({
138+
onSuccess: () => machine.send('TEST_PASS'),
139+
onFail: () => machine.send('TEST_FAIL'),
140+
})
141+
},
142+
[COMMANDS.TEST_PASS]: () => {
143+
vscode.window.showInformationMessage('PASS')
144+
},
145+
[COMMANDS.TEST_FAIL]: () => {
146+
vscode.window.showWarningMessage('FAIL')
147+
},
148+
[COMMANDS.SET_LAYOUT]: () => {
149+
console.log('setLayout')
150+
vscode.commands.executeCommand('vscode.setEditorLayout', {
151+
orientation: 0,
152+
groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }],
153+
})
154+
},
155+
}
156+
}

src/editor/index.ts

+15-14
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@ class Editor {
2727
}
2828
setWorkspaceRoot(rootPath)
2929
}
30-
31-
private activateCommands = (): void => {
32-
const commands = createCommands({
33-
context: this.context,
34-
machine: this.machine,
35-
storage,
36-
git,
37-
position,
38-
})
39-
for (const cmd in commands) {
40-
const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd])
41-
this.context.subscriptions.push(command)
42-
}
43-
}
4430
public activate = (context: vscode.ExtensionContext): void => {
4531
console.log('ACTIVATE!')
4632
this.context = context
@@ -56,13 +42,28 @@ class Editor {
5642
disposable.dispose()
5743
}
5844
// shut down state machine
45+
console.log('deactivate machine')
5946
this.machine.deactivate()
6047
}
6148

6249
// execute vscode command
6350
public dispatch = (type: string, payload?: any) => {
6451
vscode.commands.executeCommand(type, payload)
6552
}
53+
54+
private activateCommands = (): void => {
55+
const commands = createCommands({
56+
context: this.context,
57+
machine: this.machine,
58+
storage,
59+
git,
60+
position,
61+
})
62+
for (const cmd in commands) {
63+
const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd])
64+
this.context.subscriptions.push(command)
65+
}
66+
}
6667
}
6768

6869
export default Editor

src/editor/storage.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ export function get<T>(key: string): T | undefined {
1212
return storage.get(key)
1313
}
1414

15-
export function update<T>(key: string, value: string | Object): Thenable<void> {
15+
export function update<T>(key: string, value: string | object): Thenable<void> {
1616
return storage.update(key, value)
1717
}

src/services/git/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export async function gitCheckRemoteExists(): Promise<boolean> {
128128
// TODO: improve the specificity of this regex
129129
return !!stdout.match(gitOrigin)
130130
} catch (error) {
131-
console.warn(error)
132131
return false
133132
}
134133
}

src/services/position.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ export async function loadProgressPosition() {
6262
storage.setPosition(position)
6363
}
6464

65-
export async function getPrev(): Promise<void> {}
65+
export async function getPrev(): Promise<void> { }

src/state/actions/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,10 @@ export default (dispatch: CR.EditorDispatch) => ({
4343
currentTutorial = tutorial
4444
console.log('api')
4545
console.log(tutorial)
46-
dispatch('coderoad.tutorial_launch', tutorial)
46+
dispatch('coderoad.tutorial_launch', { tutorial, dispatch })
4747
},
4848
tutorialSetup() {
4949
dispatch('coderoad.tutorial_setup', currentTutorial)
50-
dispatch('coderoad.open_webview', 2)
5150
},
5251
initializeNewTutorial: assign({
5352
position: (context: any): CR.Position => {
@@ -88,6 +87,8 @@ export default (dispatch: CR.EditorDispatch) => ({
8887
const levelId = levelList.find((id: string) => !currentProgress.levels[id]) || levelList[levelList.length - 1]
8988
const { stageList } = data.levels[levelId]
9089
const stageId = stageList.find((id: string) => !currentProgress.stages[id]) || stageList[stageList.length - 1]
90+
console.log('position stepList')
91+
console.log(data.stages[stageId])
9192
const { stepList } = data.stages[stageId]
9293
const stepId = stepList.find((id: string) => !currentProgress.steps[id]) || stepList[stepList.length - 1]
9394

0 commit comments

Comments
 (0)