From 9cd81f73fa90da62a9090fc3e0f6825413e83a1f Mon Sep 17 00:00:00 2001 From: Asher Date: Mon, 7 Jan 2019 18:46:19 -0600 Subject: [PATCH] not finished --- .gitignore | 3 + README.md | 24 + package.json | 19 + packages/app/src/index.html | 86 + packages/app/src/index.scss | 144 + packages/disposable/package.json | 4 + packages/disposable/src/disposable.ts | 5 + packages/electron-browser/package.json | 8 + packages/electron-browser/src/dialog.scss | 68 + packages/electron-browser/src/dialog.ts | 194 + packages/electron-browser/src/electron.ts | 352 ++ packages/electron-browser/yarn.lock | 958 +++++ packages/ide/package.json | 5 + packages/ide/src/client.ts | 94 + packages/ide/src/index.ts | 4 + packages/ide/src/retry.ts | 344 ++ packages/ide/src/upload.ts | 367 ++ packages/ide/src/uri.ts | 45 + packages/logger/README.md | 28 + packages/logger/package.json | 5 + packages/logger/src/index.ts | 1 + packages/logger/src/logger.test.ts | 16 + packages/logger/src/logger.ts | 367 ++ packages/logger/yarn.lock | 4 + packages/node-browser/package.json | 5 + packages/node-browser/src/child_process.ts | 185 + packages/node-browser/src/empty.ts | 1 + packages/node-browser/src/fs.ts | 715 ++++ packages/node-browser/src/index.ts | 2 + packages/node-browser/src/net.ts | 70 + packages/node-browser/src/util.ts | 137 + packages/node-browser/yarn.lock | 4 + packages/package.json | 45 + packages/requirefs/package.json | 20 + packages/requirefs/src/index.ts | 1 + packages/requirefs/src/requirefs.ts | 170 + packages/requirefs/src/tarReader.ts | 285 ++ packages/requirefs/test/.gitignore | 3 + packages/requirefs/test/lib/chained-1.js | 1 + packages/requirefs/test/lib/chained-2.js | 1 + packages/requirefs/test/lib/chained-3.js | 1 + packages/requirefs/test/lib/customModule.js | 1 + packages/requirefs/test/lib/individual.js | 1 + packages/requirefs/test/lib/nodeResolve.js | 3 + .../test/lib/node_modules/frogger/index.js | 1 + packages/requirefs/test/lib/scope.js | 1 + packages/requirefs/test/lib/subfolder.js | 1 + .../requirefs/test/lib/subfolder/goingUp.js | 1 + .../requirefs/test/lib/subfolder/oranges.js | 1 + packages/requirefs/test/requirefs.bench.ts | 48 + packages/requirefs/test/requirefs.test.ts | 56 + packages/requirefs/test/requirefs.util.ts | 112 + packages/requirefs/yarn.lock | 99 + packages/rules/package.json | 7 + .../rules/src/curlyStatementNewlinesRule.ts | 37 + packages/rules/tsconfig.json | 12 + packages/rules/yarn.lock | 4 + packages/scripts/dummy.js | 1 + packages/scripts/install-packages.ts | 42 + packages/scripts/test-setup.js | 3 + packages/vscode/package.json | 4 + packages/vscode/src/element/augment.ts | 277 ++ packages/vscode/src/element/contextmenu.css | 68 + packages/vscode/src/element/contextmenu.ts | 250 ++ packages/vscode/src/entry.ts | 55 + packages/vscode/src/fill/css.js | 6 + packages/vscode/src/fill/native-keymap.ts | 8 + packages/vscode/src/fill/node-pty.ts | 73 + packages/vscode/src/firefox.scss | 9 + packages/vscode/src/firefox.ts | 20 + packages/vscode/src/storageService.ts | 58 + packages/vscode/src/upload.ts | 59 + packages/vscode/src/workbench.ts | 245 ++ packages/yarn.lock | 3787 +++++++++++++++++ tsconfig.json | 26 + tslint.json | 86 + webpack.config.app.js | 194 + webpack.config.bootstrap.js | 180 + yarn.lock | 388 ++ 79 files changed, 11015 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package.json create mode 100644 packages/app/src/index.html create mode 100644 packages/app/src/index.scss create mode 100644 packages/disposable/package.json create mode 100644 packages/disposable/src/disposable.ts create mode 100644 packages/electron-browser/package.json create mode 100644 packages/electron-browser/src/dialog.scss create mode 100644 packages/electron-browser/src/dialog.ts create mode 100644 packages/electron-browser/src/electron.ts create mode 100644 packages/electron-browser/yarn.lock create mode 100644 packages/ide/package.json create mode 100644 packages/ide/src/client.ts create mode 100644 packages/ide/src/index.ts create mode 100644 packages/ide/src/retry.ts create mode 100644 packages/ide/src/upload.ts create mode 100644 packages/ide/src/uri.ts create mode 100644 packages/logger/README.md create mode 100644 packages/logger/package.json create mode 100644 packages/logger/src/index.ts create mode 100644 packages/logger/src/logger.test.ts create mode 100644 packages/logger/src/logger.ts create mode 100644 packages/logger/yarn.lock create mode 100644 packages/node-browser/package.json create mode 100644 packages/node-browser/src/child_process.ts create mode 100644 packages/node-browser/src/empty.ts create mode 100644 packages/node-browser/src/fs.ts create mode 100644 packages/node-browser/src/index.ts create mode 100644 packages/node-browser/src/net.ts create mode 100644 packages/node-browser/src/util.ts create mode 100644 packages/node-browser/yarn.lock create mode 100644 packages/package.json create mode 100644 packages/requirefs/package.json create mode 100644 packages/requirefs/src/index.ts create mode 100644 packages/requirefs/src/requirefs.ts create mode 100644 packages/requirefs/src/tarReader.ts create mode 100644 packages/requirefs/test/.gitignore create mode 100644 packages/requirefs/test/lib/chained-1.js create mode 100644 packages/requirefs/test/lib/chained-2.js create mode 100644 packages/requirefs/test/lib/chained-3.js create mode 100644 packages/requirefs/test/lib/customModule.js create mode 100644 packages/requirefs/test/lib/individual.js create mode 100644 packages/requirefs/test/lib/nodeResolve.js create mode 100644 packages/requirefs/test/lib/node_modules/frogger/index.js create mode 100644 packages/requirefs/test/lib/scope.js create mode 100644 packages/requirefs/test/lib/subfolder.js create mode 100644 packages/requirefs/test/lib/subfolder/goingUp.js create mode 100644 packages/requirefs/test/lib/subfolder/oranges.js create mode 100644 packages/requirefs/test/requirefs.bench.ts create mode 100644 packages/requirefs/test/requirefs.test.ts create mode 100644 packages/requirefs/test/requirefs.util.ts create mode 100644 packages/requirefs/yarn.lock create mode 100644 packages/rules/package.json create mode 100644 packages/rules/src/curlyStatementNewlinesRule.ts create mode 100644 packages/rules/tsconfig.json create mode 100644 packages/rules/yarn.lock create mode 100644 packages/scripts/dummy.js create mode 100644 packages/scripts/install-packages.ts create mode 100644 packages/scripts/test-setup.js create mode 100644 packages/vscode/package.json create mode 100644 packages/vscode/src/element/augment.ts create mode 100644 packages/vscode/src/element/contextmenu.css create mode 100644 packages/vscode/src/element/contextmenu.ts create mode 100644 packages/vscode/src/entry.ts create mode 100644 packages/vscode/src/fill/css.js create mode 100644 packages/vscode/src/fill/native-keymap.ts create mode 100644 packages/vscode/src/fill/node-pty.ts create mode 100644 packages/vscode/src/firefox.scss create mode 100644 packages/vscode/src/firefox.ts create mode 100644 packages/vscode/src/storageService.ts create mode 100644 packages/vscode/src/upload.ts create mode 100644 packages/vscode/src/workbench.ts create mode 100644 packages/yarn.lock create mode 100644 tsconfig.json create mode 100644 tslint.json create mode 100644 webpack.config.app.js create mode 100644 webpack.config.bootstrap.js create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3fc94bec --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +lib/vscode +node_modules +dist diff --git a/README.md b/README.md new file mode 100644 index 00000000..88ad451e --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# vscode-cloud + +Run VS Code in the cloud. + +## Contributing + +### Getting the source + +``` +git clone https://github.com/codercom/vscode-cloud +``` + +### Installing dependencies + +``` +cd vscode-cloud +yarn +``` + +### Run + +``` +yarn start +``` diff --git a/package.json b/package.json new file mode 100644 index 00000000..1b9e170c --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "@coder/vscode-cloud", + "repository": "https://github.com/codercom/vscode-cloud", + "author": "Coder", + "license": "TBD", + "description": "VS Code in the cloud.", + "scripts": { + "vscode:clone": "mkdir -p ./lib && test -d ./lib/vscode || git clone https://github.com/Microsoft/vscode/ ./lib/vscode", + "vscode:install": "cd ./lib/vscode && git checkout tags/1.30.1 && yarn", + "vscode": "npm-run-all vscode:*", + "packages:install": "cd ./packages && yarn", + "postinstall": "npm-run-all --parallel vscode packages:install", + "start": "webpack-dev-server --config ./webpack.config.app.js", + "test": "cd ./packages && yarn test" + }, + "devDependencies": { + "npm-run-all": "^4.1.5" + } +} diff --git a/packages/app/src/index.html b/packages/app/src/index.html new file mode 100644 index 00000000..b9ab7b46 --- /dev/null +++ b/packages/app/src/index.html @@ -0,0 +1,86 @@ + + + + + + VS Code + + + +
+ +
+
+
+
+
+ +
+
+
+
+ + + + diff --git a/packages/app/src/index.scss b/packages/app/src/index.scss new file mode 100644 index 00000000..ae57f985 --- /dev/null +++ b/packages/app/src/index.scss @@ -0,0 +1,144 @@ +html, body { + height: 100%; + margin: 0; + width: 100%; +} + +#overlay { + background: rgba(0, 0, 0, 0.2); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +#overlay { + align-items: center; + background-color: #252526; + bottom: 0; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + justify-content: center; + left: 0; + opacity: 1; + position: absolute; + right: 0; + top: 0; + transition: 150ms opacity ease; + z-index: 2; +} + +#overlay>.message { + color: white; + margin-top: 10px; + opacity: 0.5; +} + +#overlay.error>.message { + color: white; + opacity: 0.3; +} + +#overlay>.activitybar { + background-color: rgb(44, 44, 44); + bottom: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 50px; +} + +#overlay>.activitybar svg { + fill: white; + margin-left: 2px; + margin-top: 2px; + opacity: 0.3; +} + +#overlay.error>#status { + opacity: 0; +} + +#overlay>.statusbar { + background-color: rgb(0, 122, 204); + bottom: 0; + cursor: default; + height: 22px; + left: 0; + position: absolute; + right: 0; +} + +#logo { + transform-style: preserve-3d; +} + +#logo>svg { + fill: rgb(0, 122, 204); + opacity: 1; + width: 100px; +} + +#status { + background: rgba(255, 255, 255, 0.1); + border-radius: 5px; + box-shadow: 0px 2px 10px -2px rgba(0, 0, 0, 0.75); + color: white; + font-size: 0.9em; + margin-top: 15px; + min-width: 100px; + position: relative; + transition: 300ms opacity ease; +} + +#status>#progress { + background: rgba(0, 0, 0, 0.2); + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + bottom: 0; + height: 3px; + left: 0; + overflow: hidden; + position: absolute; + right: 0; +} + +@-moz-keyframes statusProgress { + 0% { + background-position: 0% 50% + } + + 50% { + background-position: 100% 50% + } + + 100% { + background-position: 0% 50% + } +} + +@keyframes statusProgress { + 0% { + background-position: 0% 50% + } + + 50% { + background-position: 100% 50% + } + + 100% { + background-position: 0% 50% + } +} + +#status>#progress>#fill { + animation: statusProgress 2s ease infinite; + background-size: 400% 400%; + background: linear-gradient(270deg, #007acc, #0016cc); + height: 100%; + transition: 500ms width ease; + width: 0%; +} diff --git a/packages/disposable/package.json b/packages/disposable/package.json new file mode 100644 index 00000000..28c7886a --- /dev/null +++ b/packages/disposable/package.json @@ -0,0 +1,4 @@ +{ + "name": "@coder/disposable", + "main": "src/disposable.ts" +} diff --git a/packages/disposable/src/disposable.ts b/packages/disposable/src/disposable.ts new file mode 100644 index 00000000..273a45ad --- /dev/null +++ b/packages/disposable/src/disposable.ts @@ -0,0 +1,5 @@ +export interface IDisposable { + + dispose(): void; + +} diff --git a/packages/electron-browser/package.json b/packages/electron-browser/package.json new file mode 100644 index 00000000..1ec31a66 --- /dev/null +++ b/packages/electron-browser/package.json @@ -0,0 +1,8 @@ +{ + "name": "@coder/electron-browser", + "description": "A browser implementation of Electron's API.", + "main": "src/index.ts", + "devDependencies": { + "electron": "^4.0.1" + } +} diff --git a/packages/electron-browser/src/dialog.scss b/packages/electron-browser/src/dialog.scss new file mode 100644 index 00000000..e804f5a1 --- /dev/null +++ b/packages/electron-browser/src/dialog.scss @@ -0,0 +1,68 @@ +.msgbox { + padding-top: 25px; + padding-left: 40px; + padding-right: 40px; + padding-bottom: 25px; + background: #242424; + -webkit-box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75); + -moz-box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75); + box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75); + border-radius: 3px; +} + +.msgbox.input { + max-width: 500px; + width: 100%; +} + +.msgbox > .input { + background: #141414; + border: none; + box-sizing: border-box; + margin-bottom: 25px; + padding: 10px; + width: 100%; +} + +.msgbox > .msg { + font-size: 16px; + font-weight: bold; +} + +.msgbox > .detail { + font-size: 14px; + margin-top: 5px; +} + +.msgbox > .errors { + margin-bottom: 25px; +} + +.msgbox > .errors { + color: #f44747; +} + +.msgbox > .button-wrapper { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.msgbox > .button-wrapper > button { + flex: 1; + border-radius: 2px; + padding: 10px; + color: white; + background: #3d3d3d; + border: 0px; + cursor: pointer; + opacity: 0.8; +} + +.msgbox > .button-wrapper > button:hover { + opacity: 1; +} + +.msgbox > .button-wrapper > button:not(:last-child) { + margin-right: 8px; +} diff --git a/packages/electron-browser/src/dialog.ts b/packages/electron-browser/src/dialog.ts new file mode 100644 index 00000000..9563f05c --- /dev/null +++ b/packages/electron-browser/src/dialog.ts @@ -0,0 +1,194 @@ +import { IDisposable } from "@coder/disposable"; +import { Emitter } from "@coder/emitter"; + +import "./dialog.scss"; + +/** + * Dialog options. + */ +export interface IDialogOptions { + message?: string; + detail?: string; + buttons?: string[]; + input?: { + value: string; + selection?: { + start: number; + end: number; + }; + }; +} + +export interface IDialogAction { + buttonIndex?: number; + key?: IKey; +} + +/** + * Pressed keys. + */ +export enum IKey { + Enter = "Enter", + Escape = "Escape", +} + +export class Dialog { + + private options: IDialogOptions; + private overlay: HTMLElement; + private cachedActiveElement: HTMLElement; + private input: HTMLInputElement; + private actionEmitter: Emitter; + private errors: HTMLElement; + private buttons: HTMLElement[]; + + public constructor(options: IDialogOptions) { + this.options = options; + + this.actionEmitter = new Emitter(); + + const msgBox = document.createElement("div"); + msgBox.classList.add("msgbox"); + + if (this.options.message) { + const messageDiv = document.createElement("div"); + messageDiv.classList.add("msg"); + messageDiv.innerText = this.options.message; + msgBox.appendChild(messageDiv); + } + + if (this.options.detail) { + const detailDiv = document.createElement("div"); + detailDiv.classList.add("detail"); + detailDiv.innerText = this.options.detail; + msgBox.appendChild(detailDiv); + } + + if (this.options.input) { + msgBox.classList.add("input"); + this.input = document.createElement("input"); + this.input.classList.add("input"); + this.input.value = this.options.input.value; + this.input.addEventListener("keydown", (event) => { + if (event.key === IKey.Enter) { + event.preventDefault(); + this.actionEmitter.emit({ + buttonIndex: undefined, + key: IKey.Enter, + }); + } + }); + msgBox.appendChild(this.input); + } + + this.errors = document.createElement("div"); + this.errors.classList.add("errors"); + msgBox.appendChild(this.errors); + + if (this.options.buttons && this.options.buttons.length > 0) { + this.buttons = this.options.buttons.map((buttonText, buttonIndex) => { + const button = document.createElement("button"); + button.innerText = buttonText; + button.addEventListener("click", () => { + this.actionEmitter.emit({ + buttonIndex, + key: undefined, + }); + }); + + return button; + }); + + const buttonWrapper = document.createElement("div"); + buttonWrapper.classList.add("button-wrapper"); + this.buttons.forEach((b) => buttonWrapper.appendChild(b)); + msgBox.appendChild(buttonWrapper); + } + + + this.overlay = document.createElement("div"); + this.overlay.style.cssText = `display: flex; align-items: center; justify-content: center; top: 0; left: 0; right: 0; bottom: 0; z-index: 15; position: absolute; background: rgba(0, 0, 0, 0.4); opacity: 0; transition: 300ms opacity ease;`; + this.overlay.appendChild(msgBox); + + setTimeout(() => { + this.overlay.style.opacity = "1"; + }); + } + + /** + * Register a function to be called when the user performs an action. + */ + public onAction(callback: (action: IDialogAction) => void): IDisposable { + return this.actionEmitter.event(callback); + } + + /** + * Input value if this dialog has an input. + */ + public get inputValue(): string { + return this.input ? this.input.value : undefined; + } + + /** + * Display or remove an error. + */ + public set error(error: string) { + while (this.errors.lastChild) { + this.errors.removeChild(this.errors.lastChild); + } + if (error) { + const errorDiv = document.createElement("error"); + errorDiv.innerText = error; + this.errors.appendChild(errorDiv); + } + } + + /** + * Show the dialog. + */ + public show(): void { + if (!this.cachedActiveElement) { + this.cachedActiveElement = document.activeElement as HTMLElement; + document.body.appendChild(this.overlay); + document.addEventListener("keydown", this.onKeydown); + if (this.input) { + this.input.focus(); + if (this.options.input.selection) { + this.input.setSelectionRange( + this.options.input.selection.start, + this.options.input.selection.end + ); + } + } else if (this.buttons) { + this.buttons[0].focus(); + } + } + } + + /** + * Remove the dialog and clean up. + */ + public hide(): void { + if (this.cachedActiveElement) { + this.overlay.remove(); + document.removeEventListener("keydown", this.onKeydown); + this.cachedActiveElement.focus(); + this.cachedActiveElement = null; + } + } + + /** + * Capture escape. + */ + private onKeydown = (event: KeyboardEvent): void => { + if (event.key === "Escape") { + event.preventDefault(); + event.stopPropagation(); + this.actionEmitter.emit({ + buttonIndex: undefined, + key: IKey.Escape, + }); + } + } + +} diff --git a/packages/electron-browser/src/electron.ts b/packages/electron-browser/src/electron.ts new file mode 100644 index 00000000..27cded6b --- /dev/null +++ b/packages/electron-browser/src/electron.ts @@ -0,0 +1,352 @@ +import * as electron from "electron"; +import { EventEmitter } from "events"; +import * as fs from "fs"; +import { getFetchUrl } from "../src/coder/api"; +import { escapePath } from "../src/coder/common"; +import { wush } from "../src/coder/server"; +import { IKey, Dialog } from "./dialog"; + +(global as any).getOpenUrls = () => { + return []; +}; + +const oldCreateElement = document.createElement; + +document.createElement = (tagName: string) => { + const createElement = (tagName: string) => { + return oldCreateElement.call(document, tagName); + }; + + if (tagName === "webview") { + const view = createElement("iframe") as HTMLIFrameElement; + view.style.border = "0px"; + const frameID = Math.random().toString(); + view.addEventListener("error", (event) => { + console.log("Got iframe error", event.error, event.message); + }); + window.addEventListener("message", (event) => { + if (!event.data || !event.data.id) { + return; + } + if (event.data.id !== frameID) { + return; + } + const e = new CustomEvent("ipc-message"); + (e as any).channel = event.data.channel; + (e as any).args = event.data.data; + view.dispatchEvent(e); + }); + view.sandbox.add("allow-same-origin", "allow-scripts", "allow-popups", "allow-forms"); + Object.defineProperty(view, "preload", { + set: (url: string) => { + view.onload = () => { + view.contentDocument.body.id = frameID; + view.contentDocument.body.parentElement.style.overflow = "hidden"; + const script = document.createElement("script"); + script.src = url; + view.contentDocument.head.appendChild(script); + }; + }, + }); + (view as any).getWebContents = () => undefined; + (view as any).send = (channel: string, ...args) => { + if (args[0] && typeof args[0] === "object" && args[0].contents) { + args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m) => `"${getFetchUrl(m)}"`); + args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m) => `"${getFetchUrl(m)}"`); + } + view.contentWindow.postMessage({ + channel, + data: args, + id: frameID, + }, "*"); + }; + return view; + } + + return createElement(tagName); +}; + +const rendererToMainEmitter = new EventEmitter(); +const mainToRendererEmitter = new EventEmitter(); + +module.exports = { + clipboard: { + has: () => { + return false; + }, + writeText: (value: string) => { + // Taken from https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f + const active = document.activeElement as HTMLElement; + const el = document.createElement('textarea'); // Create a