diff --git a/src/vs/workbench/electron-browser/workbench.main.ts b/src/vs/workbench/electron-browser/workbench.main.ts
index 0bc7c2d9ac928..5d24296aa63f8 100644
--- a/src/vs/workbench/electron-browser/workbench.main.ts
+++ b/src/vs/workbench/electron-browser/workbench.main.ts
@@ -61,6 +61,8 @@ import 'vs/workbench/parts/markers/browser/markersPanel'; // can be packaged sep
import 'vs/workbench/parts/html/browser/html.contribution';
+import 'vs/workbench/parts/walkThrough/electron-browser/walkThrough.contribution';
+
import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution';
import 'vs/workbench/parts/extensions/browser/extensionsQuickOpen';
import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately
diff --git a/src/vs/workbench/parts/walkThrough/common/walkThroughInput.ts b/src/vs/workbench/parts/walkThrough/common/walkThroughInput.ts
new file mode 100644
index 0000000000000..8fe7794ec6e51
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/common/walkThroughInput.ts
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+
+import URI from 'vs/base/common/uri';
+import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
+import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
+
+export class WalkThroughInput extends ResourceEditorInput {
+
+ // just a marker class
+ constructor(
+ name: string,
+ description: string,
+ resource: URI,
+ public readonly onReady: (container: HTMLElement) => void,
+ @ITextModelResolverService textModelResolverService: ITextModelResolverService
+ ) {
+ super(name, description, resource, textModelResolverService);
+ }
+
+ getResource(): URI {
+ return this.resource;
+ }
+}
diff --git a/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.md b/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.md
new file mode 100644
index 0000000000000..a9b7355c9d4a3
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.md
@@ -0,0 +1,31 @@
+### Multi-Cursor Editing
+
+Use ⇧⌥Shift+Alt while selecting text with the mouse to select a rectangular area and change multiple lines at once.
+
+```css
+.global-message-list.transition {
+ -webkit-transition: top 200ms linear;
+ -ms-transition: top 200ms linear;
+ -moz-transition: top 200ms linear;
+ -khtml-transition: top 200ms linear;
+ -o-transition: top 200ms linear;
+ transition: top 200ms linear;
+}
+```
+
+### IntelliSense
+
+Visual Studio Code comes with powerful IntelliSense for JavaScript and TypeScript preinstalled. Other languages can be upgraded with better IntelliSense through one of the many [extensions](command:workbench.extensions.action.showPopularExtensions).
+
+In the below example, position the text cursor in front of the error underline, right after the dot and press to invoke IntelliSense.
+
+```js
+var express = require('express');
+var app = express();
+
+app.get('/', function (req, res) {
+ res.send(`Hello ${req.}`);
+});
+
+app.listen(3000);
+```
\ No newline at end of file
diff --git a/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.ts b/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.ts
new file mode 100644
index 0000000000000..0471ffd9f634f
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough.ts
@@ -0,0 +1,36 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+
+import { localize } from 'vs/nls';
+import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
+import { Position } from 'vs/platform/editor/common/editor';
+import { Action } from 'vs/base/common/actions';
+import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
+import { TPromise } from 'vs/base/common/winjs.base';
+import URI from 'vs/base/common/uri';
+import { WalkThroughInput } from 'vs/workbench/parts/walkThrough/common/walkThroughInput';
+
+export class EditorWalkThroughAction extends Action {
+
+ public static ID = 'workbench.action.editorWalkThrough';
+ public static LABEL = localize('editorWalkThrough', "Editor Walk-Through");
+
+ constructor(
+ id: string,
+ label: string,
+ @IWorkbenchEditorService private editorService: IWorkbenchEditorService,
+ @IInstantiationService private instantiationService: IInstantiationService
+ ) {
+ super(id, label);
+ }
+
+ public run(): TPromise {
+ const uri = URI.parse(require.toUrl('./editorWalkThrough.md'));
+ const input = this.instantiationService.createInstance(WalkThroughInput, localize('editorWalkThrough.title', "Editor Walk-Through"), '', uri, null);
+ return this.editorService.openEditor(input, { pinned: true }, Position.ONE)
+ .then(() => void (0));
+ }
+}
\ No newline at end of file
diff --git a/src/vs/workbench/parts/walkThrough/electron-browser/walkThrough.contribution.ts b/src/vs/workbench/parts/walkThrough/electron-browser/walkThrough.contribution.ts
new file mode 100644
index 0000000000000..98072f898da39
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/electron-browser/walkThrough.contribution.ts
@@ -0,0 +1,25 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+
+import { localize } from 'vs/nls';
+import { WalkThroughInput } from 'vs/workbench/parts/walkThrough/common/walkThroughInput';
+import { WalkThroughPart } from 'vs/workbench/parts/walkThrough/electron-browser/walkThroughPart';
+import { EditorWalkThroughAction } from 'vs/workbench/parts/walkThrough/electron-browser/editor/editorWalkThrough';
+import { Registry } from 'vs/platform/platform';
+import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
+import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
+import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
+import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
+import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
+
+(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(WalkThroughPart.ID,
+ localize('walkThrough.editor.label', "Walk-Through"),
+ 'vs/workbench/parts/walkThrough/electron-browser/walkThroughPart',
+ 'WalkThroughPart'),
+ [new SyncDescriptor(WalkThroughInput)]);
+
+Registry.as(Extensions.WorkbenchActions)
+ .registerWorkbenchAction(new SyncActionDescriptor(EditorWalkThroughAction, EditorWalkThroughAction.ID, EditorWalkThroughAction.LABEL), 'Help: Editor Walk-Through', localize('help', "Help"));
diff --git a/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.css b/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.css
new file mode 100644
index 0000000000000..232c9e189d2ba
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.css
@@ -0,0 +1,126 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent {
+ box-sizing: border-box;
+ padding: 10px 20px;
+ line-height: 22px;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent img {
+ max-width: 100%;
+ max-height: 100%;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent a {
+ color: #4080D0;
+ text-decoration: none;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent a:focus,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent input:focus,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent select:focus,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent textarea:focus {
+ outline: 1px solid -webkit-focus-ring-color;
+ outline-offset: -1px;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent hr {
+ border: 0;
+ height: 2px;
+ border-bottom: 2px solid;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent h1 {
+ padding-bottom: 0.3em;
+ line-height: 1.2;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent h1, h2, h3 {
+ font-weight: normal;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent a:hover {
+ color: #4080D0;
+ text-decoration: underline;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table {
+ border-collapse: collapse;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > thead > tr > th {
+ text-align: left;
+ border-bottom: 1px solid;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > thead > tr > th,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > thead > tr > td,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > tbody > tr > th,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > tbody > tr > td {
+ padding: 5px 10px;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent table > tbody > tr + tr > td {
+ border-top: 1px solid;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent blockquote {
+ margin: 0 7px 0 5px;
+ padding: 0 16px 0 10px;
+ border-left: 5px solid;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent code {
+ font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
+ font-size: 14px;
+ line-height: 19px;
+}
+
+.monaco-workbench.mac > .part.editor > .content .walkThroughContainer .walkThroughContent code {
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent code > div {
+ padding: 16px;
+ border-radius: 3px;
+ overflow: auto;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .monaco-tokenized-source {
+ white-space: pre;
+}
+
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .mac-only,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .windows-only,
+.monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .linux-only {
+ display: none;
+}
+.monaco-workbench.mac > .part.editor > .content .walkThroughContainer .walkThroughContent .mac-only {
+ display: initial;
+}
+.monaco-workbench.windows > .part.editor > .content .walkThroughContainer .walkThroughContent .windows-only {
+ display: initial;
+}
+.monaco-workbench.linux > .part.editor > .content .walkThroughContainer .walkThroughContent .linux-only {
+ display: initial;
+}
+
+.vs .monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .monaco-editor-background,
+.vs .monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .glyph-margin {
+ background-color: #eee;
+}
+
+.vs-dark .monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .monaco-editor-background,
+.vs-dark .monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .glyph-margin {
+ background-color: #111;
+}
+
+.hc-black .monaco-workbench > .part.editor > .content .walkThroughContainer .walkThroughContent .monaco-editor {
+ border: 1px white solid
+}
diff --git a/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.ts b/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.ts
new file mode 100644
index 0000000000000..629241167c15c
--- /dev/null
+++ b/src/vs/workbench/parts/walkThrough/electron-browser/walkThroughPart.ts
@@ -0,0 +1,223 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+'use strict';
+
+import 'vs/css!./walkThroughPart';
+import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
+import { ScrollbarVisibility } from 'vs/base/common/scrollable';
+import * as strings from 'vs/base/common/strings';
+import URI from 'vs/base/common/uri';
+import { TPromise } from 'vs/base/common/winjs.base';
+import { DefaultConfig } from 'vs/editor/common/config/defaultConfig';
+import { IEditorOptions, IModel } from 'vs/editor/common/editorCommon';
+import { $, Dimension, Builder } from 'vs/base/browser/builder';
+import { IDisposable, dispose } from 'vs/base/common/lifecycle';
+import { EditorOptions } from 'vs/workbench/common/editor';
+import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
+import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
+import { WalkThroughInput } from 'vs/workbench/parts/walkThrough/common/walkThroughInput';
+import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
+import { IOpenerService } from 'vs/platform/opener/common/opener';
+import { marked } from 'vs/base/common/marked/marked';
+import { IModeService } from 'vs/editor/common/services/modeService';
+import { IFileService } from 'vs/platform/files/common/files';
+import { IModelService } from 'vs/editor/common/services/modelService';
+import * as uuid from 'vs/base/common/uuid';
+import { CodeEditor } from 'vs/editor/browser/codeEditor';
+import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
+import * as path from 'path';
+import { tmpdir } from 'os';
+import { mkdirp } from 'vs/base/node/extfs';
+import { IMode } from 'vs/editor/common/modes';
+import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
+import { localize } from 'vs/nls';
+
+const UNBOUND_COMMAND = localize('walkThrough.unboundCommand', "unbound");
+
+export class WalkThroughPart extends BaseEditor {
+
+ static ID: string = 'workbench.editor.walkThroughPart';
+
+ private disposables: IDisposable[] = [];
+ private contentDisposables: IDisposable[] = [];
+ private content: HTMLDivElement;
+ private scrollbar: DomScrollableElement;
+
+ constructor(
+ @ITelemetryService telemetryService: ITelemetryService,
+ @IInstantiationService private instantiationService: IInstantiationService,
+ @IThemeService private themeService: IThemeService,
+ @IOpenerService private openerService: IOpenerService,
+ @IFileService private fileService: IFileService,
+ @IModelService protected modelService: IModelService,
+ @IKeybindingService private keybindingService: IKeybindingService,
+ @IModeService private modeService: IModeService
+ ) {
+ super(WalkThroughPart.ID, telemetryService);
+ }
+
+ createEditor(parent: Builder): void {
+ const container = parent.getHTMLElement();
+ container.classList.add('walkThroughContainer');
+
+ this.content = document.createElement('div');
+ this.content.classList.add('walkThroughContent');
+
+ this.scrollbar = new DomScrollableElement(this.content, {
+ canUseTranslate3d: false,
+ horizontal: ScrollbarVisibility.Auto,
+ vertical: ScrollbarVisibility.Auto
+ });
+ this.disposables.push(this.scrollbar);
+ container.appendChild(this.scrollbar.getDomNode());
+
+ this.registerClickHandler();
+ }
+
+ private registerClickHandler() {
+ this.content.addEventListener('click', event => {
+ let node = event.target;
+ if (node instanceof HTMLAnchorElement && node.href) {
+ let baseElement = window.document.getElementsByTagName('base')[0];
+ if (baseElement && node.href.indexOf(baseElement.href) >= 0 && node.hash) {
+ let scrollTarget = window.document.getElementById(node.hash.substr(1, node.hash.length - 1));
+ if (scrollTarget) {
+ scrollTarget.scrollIntoView();
+ }
+ } else {
+ this.openerService.open(URI.parse(node.href));
+ }
+ event.preventDefault();
+ } else if (node instanceof HTMLButtonElement) {
+ const href = node.getAttribute('data-href');
+ if (href) {
+ this.openerService.open(URI.parse(href));
+ }
+ }
+ });
+ }
+
+ layout({ width, height }: Dimension): void {
+ $(this.content).style({ height: `${height}px`, width: `${width}px` });
+ this.contentDisposables.forEach(disposable => {
+ if (disposable instanceof CodeEditor) {
+ disposable.layout();
+ }
+ });
+ this.scrollbar.scanDomNode();
+ }
+
+ focus(): void {
+ this.content.focus();
+ }
+
+ setInput(input: WalkThroughInput, options: EditorOptions): TPromise {
+ this.contentDisposables = dispose(this.contentDisposables);
+ this.content.innerHTML = '';
+
+ const folderName = path.join(tmpdir(), 'vscode-walk-through', uuid.generateUuid());
+ const folder = new TPromise((c, e) => mkdirp(folderName, null, err => err ? e(err) : c(folderName)));
+
+ return super.setInput(input, options)
+ .then(() => this.fileService.resolveContent(input.getResource(), { acceptTextOnly: true }))
+ .then(content => {
+ if (strings.endsWith(input.getResource().path, '.html')) {
+ this.content.innerHTML = content.value;
+ this.decorateContent();
+ if (input.onReady) {
+ input.onReady(this.content);
+ }
+ this.scrollbar.scanDomNode();
+ return;
+ }
+
+ const files: TPromise[] = [];
+ const codes: { id: string; model: IModel }[] = [];
+ const renderer = new marked.Renderer();
+ renderer.code = (code, lang) => {
+ const id = `code-${uuid.generateUuid()}`;
+ const mode = this.getModeForLanguage(lang);
+ const resource = URI.file(path.join(folderName, `${id}.${lang}`));
+ const model = this.modelService.createModel(code, mode, resource);
+ codes.push({ id, model });
+
+ // E.g., the TypeScript service needs files on disk.
+ files.push(folder.then(() => this.fileService.createFile(resource, code)));
+
+ return ``;
+ };
+ this.content.innerHTML = marked(content.value, { renderer });
+ this.decorateContent();
+
+ // TODO: also create jsconfig.json and tsconfig.json
+ return TPromise.join(files).then(() => {
+ codes.forEach(({ id, model }) => {
+ const div = this.content.querySelector(`#${id}`) as HTMLElement;
+
+ var options: IEditorOptions = {
+ scrollBeyondLastLine: false,
+ scrollbar: DefaultConfig.editor.scrollbar,
+ overviewRulerLanes: 3,
+ fixedOverflowWidgets: true,
+ lineNumbersMinChars: 1,
+ theme: this.themeService.getColorTheme().id,
+ };
+
+ const editor = this.instantiationService.createInstance(CodeEditor, div, options);
+ editor.setModel(model);
+ this.contentDisposables.push(editor);
+
+ const lineHeight = editor.getConfiguration().lineHeight;
+ const height = model.getLineCount() * lineHeight;
+ div.style.height = height + 'px';
+
+ this.contentDisposables.push(this.themeService.onDidColorThemeChange(theme => editor.updateOptions({ theme: theme.id })));
+
+ editor.layout();
+ });
+ if (input.onReady) {
+ input.onReady(this.content);
+ }
+ this.scrollbar.scanDomNode();
+ });
+ });
+ }
+
+ private getModeForLanguage(lang: string): TPromise {
+ return new TPromise(c => {
+ const that = this;
+ function tryGetMode() {
+ const modeId = that.modeService.getModeIdForLanguageName(lang);
+ const mode = modeId && that.modeService.getOrCreateMode(modeId);
+ if (mode) {
+ c(mode);
+ } else {
+ const subscription = that.modeService.onDidAddModes(() => {
+ subscription.dispose();
+ tryGetMode();
+ });
+ }
+ }
+ tryGetMode();
+ });
+ }
+
+ private decorateContent() {
+ const keys = this.content.querySelectorAll('.shortcut[data-command]');
+ Array.prototype.forEach.call(keys, (key: Element) => {
+ const command = key.getAttribute('data-command');
+ const keybinding = command && this.keybindingService.lookupKeybindings(command)[0];
+ const label = keybinding ? this.keybindingService.getLabelFor(keybinding) : UNBOUND_COMMAND;
+ key.appendChild(document.createTextNode(label));
+ });
+ }
+
+ dispose(): void {
+ this.contentDisposables = dispose(this.contentDisposables);
+ this.disposables = dispose(this.disposables);
+ super.dispose();
+ }
+}