Skip to content

Feature/tutorial setup #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 9, 2019
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
progress refactoring webview, editor, machine
  • Loading branch information
ShMcK committed Jun 8, 2019
commit d00a485520f4e121797b8531695aa02e47d3d28a
146 changes: 146 additions & 0 deletions src/editor/ReactWebView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import * as vscode from 'vscode'
import * as CR from 'typings'
import * as path from 'path'

function getNonce(): string {
let text = ''
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}

// TODO: move column into createOrShow


/**
* Manages React webview panels
*/
class ReactWebView {
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
public static currentPanel: ReactWebView | undefined = undefined

// @ts-ignore
private panel: vscode.WebviewPanel
private extensionPath: string
private disposables: vscode.Disposable[] = []
private onReceive: any // TODO: properly type

public constructor(extensionPath: string, onReceive: any) {
this.extensionPath = extensionPath
this.onReceive = onReceive
}

public async createOrShow(extensionPath: string, column: number = vscode.ViewColumn.One): Promise<void> {
const hasActiveEditor = vscode.window.activeTextEditor

if (!hasActiveEditor) {
throw new Error('Should have an open file on launch')
}

// If we already have a panel, show it.
// Otherwise, create a new panel.
if (ReactWebView.currentPanel && ReactWebView.currentPanel.panel) {
ReactWebView.currentPanel.panel.reveal(column)
} else {
const viewType = 'CodeRoad'
const title = 'CodeRoad'
const config = {
// Enable javascript in the webview
enableScripts: true,

// And restric the webview to only loading content from our extension's `media` directory.
localResourceRoots: [vscode.Uri.file(path.join(this.extensionPath, 'build'))],

// prevents destroying the window when it is in the background
retainContextWhenHidden: true,
}
// Create and show a new webview panel
this.panel = vscode.window.createWebviewPanel(viewType, title, column, config)

// Set the webview's initial html content
this.panel.webview.html = this.getHtmlForWebview()

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

// Handle messages from the webview
this.panel.webview.onDidReceiveMessage(this.onReceive, null, this.disposables)
}
}

public async postMessage(action: CR.Action): Promise<void> {
// Send a message to the webview webview.
// You can send any JSON serializable data.
const success = await this.panel.webview.postMessage(action)
if (!success) {
throw new Error(`Message post failure: ${JSON.stringify(action)}`)
}
}

public dispose(): void {
ReactWebView.currentPanel = undefined

// Clean up our resources
this.panel.dispose()

while (this.disposables.length) {
const x = this.disposables.pop()
if (x) {
x.dispose()
}
}
}

private getHtmlForWebview(): string {

// eslint-disable-next-line
const manifest = require(path.join(this.extensionPath, 'build', 'asset-manifest.json'))
const mainScript = manifest.files['main.js']
// grab first chunk
const chunk = Object.keys(manifest.files).filter(f => f.match(/^static\/js\/.+\.js$/))[0]
const chunkScript = manifest.files[chunk]
const mainStyle = manifest.files['main.css']

const scriptPathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainScript))
const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' })
const chunkPathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', chunkScript))
const chunkUri = chunkPathOnDisk.with({ scheme: 'vscode-resource' })
const stylePathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainStyle))
const styleUri = stylePathOnDisk.with({ scheme: 'vscode-resource' })

// Use a nonce to whitelist which scripts can be run
const nonce = getNonce()
const nonce2 = getNonce()
const nonce3 = getNonce()

return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>React App</title>
<link rel="manifest" href="./manifest.json" />
<link rel="stylesheet" type="text/css" href="${styleUri}">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-${nonce}' 'nonce-${nonce2}' 'nonce-${nonce3}'; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
<base href="${vscode.Uri.file(path.join(this.extensionPath, 'build')).with({ scheme: 'vscode-resource' })}/">
<style></style>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">Loading...</div>
<script nonce=${nonce} src="./webpackBuild.js"></script>
<script nonce=${nonce2} src="${chunkUri}"></script>
<script nonce="${nonce3}" src="${scriptUri}"></script>
</body>
</html>`
}
}

export default ReactWebView
4 changes: 2 additions & 2 deletions src/editor/commands/start.ts
Original file line number Diff line number Diff line change
@@ -18,9 +18,9 @@ export default async function start(context: vscode.ExtensionContext): Promise<v
console.log('TUTORIAL_START')

// setup connection to workspace
await setWorkspaceRoot()
// await setWorkspaceRoot()
// set workspace context path
await setStorage(context.workspaceState)
// await setStorage(context.workspaceState)

// initialize state machine
activateMachine()
75 changes: 75 additions & 0 deletions src/editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as vscode from 'vscode'
import * as CR from '../typings'
import { setStorage } from './storage'
import ReactWebView from './ReactWebView'

class Editor {
// extension context set on activation
// @ts-ignore
private context: vscode.ExtensionContext
private workspaceRoot: string | undefined
private machine: CR.StateMachine
private webview: any

private COMMANDS = {
START: 'coderoad.start',
OPEN_WEBVIEW: 'coderoad.open_webview',
RUN_TEST: 'coderoad.test_run',
}

constructor(machine: CR.StateMachine) {
this.machine = machine
}

private commandStart() {
// set workspace root
const { rootPath } = vscode.workspace
if (!rootPath) {
throw new Error('Requires a workspace. Please open a folder')
}
this.workspaceRoot = rootPath

// set local storage workspace
setStorage(this.context.workspaceState)

// activate machine
this.machine.activate()
this.webview = new ReactWebView(this.context.extensionPath, this.machine.onReceive)
}

private activateCommands() {
const { COMMANDS } = this
const commands = {
[COMMANDS.START]: () => {
this.commandStart()
},
[COMMANDS.OPEN_WEBVIEW]: () => {
this.webview.createOrShow(this.context.extensionPath);
},
}
for (const cmd in commands) {
const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd])
this.context.subscriptions.push(command)
}
}
public activate(context: vscode.ExtensionContext): void {
console.log('ACTIVATE!')
this.context = context
// commands
this.activateCommands()

// setup tasks or views here

}
public deactivate(): void {
console.log('DEACTIVATE!')
// cleanup subscriptions/tasks
for (const disposable of this.context.subscriptions) {
disposable.dispose()
}
// shut down state machine
this.machine.deactivate()
}
}

export default Editor
33 changes: 0 additions & 33 deletions src/editor/init.ts

This file was deleted.

Loading
Oops, something went wrong.