提交 6f4cea3b 编写于 作者: C Christof Marti

Walk-Through Editor

上级 216608a3
......@@ -60,6 +60,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
......
/*---------------------------------------------------------------------------------------------
* 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;
}
}
### Multi-Cursor Editing
Use <span class="shortcut mac-only">⇧⌥</span><span class="shortcut windows-only linux-only">Shift+Alt</span> 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 <span class="shortcut" data-command="editor.action.triggerSuggest"></span> 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
/*---------------------------------------------------------------------------------------------
* 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<void> {
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
/*---------------------------------------------------------------------------------------------
* 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';
(<IEditorRegistry>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<IWorkbenchActionRegistry>(Extensions.WorkbenchActions)
.registerWorkbenchAction(new SyncActionDescriptor(EditorWalkThroughAction, EditorWalkThroughAction.ID, EditorWalkThroughAction.LABEL), 'Help: Editor Walk-Through', localize('help', "Help"));
/*---------------------------------------------------------------------------------------------
* 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
}
/*---------------------------------------------------------------------------------------------
* 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<void> {
this.contentDisposables = dispose(this.contentDisposables);
this.content.innerHTML = '';
const folderName = path.join(tmpdir(), 'vscode-walk-through', uuid.generateUuid());
const folder = new TPromise<string>((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<any>[] = [];
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 `<div id=${id} class="walkThroughEditorContainer" ></div>`;
};
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(),
};
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 })));
editor.layout();
});
if (input.onReady) {
input.onReady(this.content);
}
this.scrollbar.scanDomNode();
});
});
}
private getModeForLanguage(lang: string): TPromise<IMode> {
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();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册