Revert "Pretter for each ts file"

This reverts commit 23674b2cfe.
This commit is contained in:
Pine Wu
2018-10-23 22:14:56 -07:00
parent e01af61527
commit b72fae94fa
55 changed files with 1477 additions and 1753 deletions

View File

@ -1,5 +0,0 @@
{
"useTabs": true,
"printWidth": 120,
"singleQuote": true
}

View File

@ -4,81 +4,71 @@
'use strict';
import {
ExtensionContext,
StatusBarAlignment,
window,
StatusBarItem,
Selection,
workspace,
TextEditor,
commands
} from 'vscode';
import { ExtensionContext, StatusBarAlignment, window, StatusBarItem, Selection, workspace, TextEditor, commands } from 'vscode';
import { basename } from 'path';
export function activate(context: ExtensionContext) {
// Create a status bar item
const status = window.createStatusBarItem(StatusBarAlignment.Left, 1000000);
context.subscriptions.push(status);
// Update status bar item based on events for multi root folder changes
context.subscriptions.push(workspace.onDidChangeWorkspaceFolders(e => updateStatus(status)));
// Create a status bar item
const status = window.createStatusBarItem(StatusBarAlignment.Left, 1000000);
context.subscriptions.push(status);
// Update status bar item based on events for configuration
context.subscriptions.push(workspace.onDidChangeConfiguration(e => this.updateStatus(status)));
// Update status bar item based on events for multi root folder changes
context.subscriptions.push(workspace.onDidChangeWorkspaceFolders(e => updateStatus(status)));
// Update status bar item based on events around the active editor
context.subscriptions.push(window.onDidChangeActiveTextEditor(e => updateStatus(status)));
context.subscriptions.push(window.onDidChangeTextEditorViewColumn(e => updateStatus(status)));
context.subscriptions.push(workspace.onDidOpenTextDocument(e => updateStatus(status)));
context.subscriptions.push(workspace.onDidCloseTextDocument(e => updateStatus(status)));
// Update status bar item based on events for configuration
context.subscriptions.push(workspace.onDidChangeConfiguration(e => this.updateStatus(status)));
updateStatus(status);
// Update status bar item based on events around the active editor
context.subscriptions.push(window.onDidChangeActiveTextEditor(e => updateStatus(status)));
context.subscriptions.push(window.onDidChangeTextEditorViewColumn(e => updateStatus(status)));
context.subscriptions.push(workspace.onDidOpenTextDocument(e => updateStatus(status)));
context.subscriptions.push(workspace.onDidCloseTextDocument(e => updateStatus(status)));
updateStatus(status);
}
function updateStatus(status: StatusBarItem): void {
const info = getEditorInfo();
status.text = info ? info.text : void 0;
status.tooltip = info ? info.tooltip : void 0;
status.color = info ? info.color : void 0;
const info = getEditorInfo();
status.text = info ? info.text : void 0;
status.tooltip = info ? info.tooltip : void 0;
status.color = info ? info.color : void 0;
if (info) {
status.show();
} else {
status.hide();
}
if (info) {
status.show();
} else {
status.hide();
}
}
function getEditorInfo(): { text: string; tooltip: string; color: string } {
const editor = window.activeTextEditor;
function getEditorInfo(): { text: string; tooltip: string; color: string; } {
const editor = window.activeTextEditor;
// If no workspace is opened or just a single folder, we return without any status label
// because our extension only works when more than one folder is opened in a workspace.
if (!editor || !workspace.workspaceFolders || workspace.workspaceFolders.length < 2) {
return null;
}
// If no workspace is opened or just a single folder, we return without any status label
// because our extension only works when more than one folder is opened in a workspace.
if (!editor || !workspace.workspaceFolders || workspace.workspaceFolders.length < 2) {
return null;
}
let text: string;
let tooltip: string;
let color: string;
let text: string;
let tooltip: string;
let color: string;
// If we have a file:// resource we resolve the WorkspaceFolder this file is from and update
// the status accordingly.
const resource = editor.document.uri;
if (resource.scheme === 'file') {
const folder = workspace.getWorkspaceFolder(resource);
if (!folder) {
text = `$(alert) <outside workspace> → ${basename(resource.fsPath)}`;
} else {
text = `$(file-submodule) ${basename(folder.uri.fsPath)} (${folder.index + 1} of ${
workspace.workspaceFolders.length
}) → $(file-code) ${basename(resource.fsPath)}`;
tooltip = resource.fsPath;
// If we have a file:// resource we resolve the WorkspaceFolder this file is from and update
// the status accordingly.
const resource = editor.document.uri;
if (resource.scheme === 'file') {
const folder = workspace.getWorkspaceFolder(resource);
if (!folder) {
text = `$(alert) <outside workspace> → ${basename(resource.fsPath)}`;
} else {
text = `$(file-submodule) ${basename(folder.uri.fsPath)} (${folder.index + 1} of ${workspace.workspaceFolders.length}) → $(file-code) ${basename(resource.fsPath)}`;
tooltip = resource.fsPath;
const multiRootConfigForResource = workspace.getConfiguration('multiRootSample', resource);
color = multiRootConfigForResource.get('statusColor');
}
}
const multiRootConfigForResource = workspace.getConfiguration('multiRootSample', resource);
color = multiRootConfigForResource.get('statusColor');
}
}
return { text, tooltip, color };
return { text, tooltip, color };
}

View File

@ -7,22 +7,22 @@
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// The most simple completion item provider which
// The most simple completion item provider which
// * registers for text files (`'plaintext'`), and
// * return the 'Hello World' and
// * return the 'Hello World' and
// a snippet-based completion item.
vscode.languages.registerCompletionItemProvider('plaintext', {
provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken,
context: vscode.CompletionContext
) {
return [new vscode.CompletionItem('Hello World!'), createSnippetItem()];
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
return [
new vscode.CompletionItem('Hello World!'),
createSnippetItem()
];
}
});
function createSnippetItem(): vscode.CompletionItem {
// Read more here:
// https://code.visualstudio.com/docs/extensionAPI/vscode-api#CompletionItem
// https://code.visualstudio.com/docs/extensionAPI/vscode-api#SnippetString
@ -31,10 +31,8 @@ export function activate(context: vscode.ExtensionContext) {
// https://code.visualstudio.com/docs/editor/userdefinedsnippets#_creating-your-own-snippets
let item = new vscode.CompletionItem('Good part of the day', vscode.CompletionItemKind.Snippet);
item.insertText = new vscode.SnippetString('Good ${1|morning,afternoon,evening|}. It is ${1}, right?');
item.documentation = new vscode.MarkdownString(
'Inserts a snippet that lets you select the _appropriate_ part of the day for your greeting.'
);
item.insertText = new vscode.SnippetString("Good ${1|morning,afternoon,evening|}. It is ${1}, right?");
item.documentation = new vscode.MarkdownString("Inserts a snippet that lets you select the _appropriate_ part of the day for your greeting.");
return item;
}

View File

@ -1,6 +1,7 @@
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// Example 1: Reading Window scoped configuration
const configuredView = vscode.workspace.getConfiguration().get('conf.view.showOnWindowOpen');
switch (configuredView) {
@ -23,22 +24,22 @@ export function activate(context: vscode.ExtensionContext) {
// Example 2: Updating Window scoped configuration
vscode.commands.registerCommand('config.commands.configureViewOnWindowOpen', async () => {
// 1) Getting the value
const value = await vscode.window.showQuickPick(['explorer', 'search', 'scm', 'debug', 'extensions'], {
placeHolder: 'Select the view to show when opening a window.'
});
const value = await vscode.window.showQuickPick(['explorer', 'search', 'scm', 'debug', 'extensions'], { placeHolder: 'Select the view to show when opening a window.' });
if (vscode.workspace.workspaceFolders) {
// 2) Getting the Configuration target
const target = await vscode.window.showQuickPick(
[
{ label: 'User', description: 'User Settings', target: vscode.ConfigurationTarget.Global },
{ label: 'Workspace', description: 'Workspace Settings', target: vscode.ConfigurationTarget.Workspace }
],
{ placeHolder: 'Select the view to show when opening a window.' }
);
{ placeHolder: 'Select the view to show when opening a window.' });
if (value && target) {
// 3) Update the configuration value in the target
await vscode.workspace.getConfiguration().update('conf.view.showOnWindowOpen', value, target.target);
@ -48,31 +49,33 @@ export function activate(context: vscode.ExtensionContext) {
*/
}
} else {
// 2) Update the configuration value in User Setting in case of no workspace folders
await vscode.workspace
.getConfiguration()
.update('conf.view.showOnWindowOpen', value, vscode.ConfigurationTarget.Global);
await vscode.workspace.getConfiguration().update('conf.view.showOnWindowOpen', value, vscode.ConfigurationTarget.Global);
}
});
// Example 3: Reading Resource scoped configuration for a file
context.subscriptions.push(
vscode.workspace.onDidOpenTextDocument(e => {
// 1) Get the configured glob pattern value for the current file
const value = vscode.workspace.getConfiguration('', e.uri).get('conf.resource.insertEmptyLastLine');
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(e => {
// 2) Check if the current resource matches the glob pattern
const matches = value[e.fileName];
// 1) Get the configured glob pattern value for the current file
const value = vscode.workspace.getConfiguration('', e.uri).get('conf.resource.insertEmptyLastLine');
// 3) If matches, insert empty last line
if (matches) {
vscode.window.showInformationMessage('An empty line will be added to the document ' + e.fileName);
}
})
);
// 2) Check if the current resource matches the glob pattern
const matches = value[e.fileName];
// 3) If matches, insert empty last line
if (matches) {
vscode.window.showInformationMessage('An empty line will be added to the document ' + e.fileName);
}
}));
// Example 4: Updating Resource scoped Configuration for current file
vscode.commands.registerCommand('config.commands.configureEmptyLastLineCurrentFile', async () => {
if (vscode.window.activeTextEditor) {
const currentDocument = vscode.window.activeTextEditor.document;
@ -83,46 +86,41 @@ export function activate(context: vscode.ExtensionContext) {
const currentValue = configuration.get('conf.resource.insertEmptyLastLine', {});
// 3) Choose target to Global when there are no workspace folders
const target = vscode.workspace.workspaceFolders
? vscode.ConfigurationTarget.WorkspaceFolder
: vscode.ConfigurationTarget.Global;
const target = vscode.workspace.workspaceFolders ? vscode.ConfigurationTarget.WorkspaceFolder : vscode.ConfigurationTarget.Global;
const value = { ...currentValue, ...{ [currentDocument.fileName]: true } };
// 4) Update the configuration
await configuration.update('conf.resource.insertEmptyLastLine', value, target);
await configuration.update('conf.resource.insertEmptyLastLine', value, target)
}
});
// Example 5: Updating Resource scoped Configuration
vscode.commands.registerCommand('config.commands.configureEmptyLastLineFiles', async () => {
// 1) Getting the value
const value = await vscode.window.showInputBox({
prompt: 'Provide glob pattern of files to have empty last line.'
});
const value = await vscode.window.showInputBox({ prompt: 'Provide glob pattern of files to have empty last line.' });
if (vscode.workspace.workspaceFolders) {
// 2) Getting the target
const target = await vscode.window.showQuickPick(
[
{ label: 'Application', description: 'User Settings', target: vscode.ConfigurationTarget.Global },
{ label: 'Workspace', description: 'Workspace Settings', target: vscode.ConfigurationTarget.Workspace },
{
label: 'Workspace Folder',
description: 'Workspace Folder Settings',
target: vscode.ConfigurationTarget.WorkspaceFolder
}
{ label: 'Workspace Folder', description: 'Workspace Folder Settings', target: vscode.ConfigurationTarget.WorkspaceFolder }
],
{ placeHolder: 'Select the target to which this setting should be applied' }
);
{ placeHolder: 'Select the target to which this setting should be applied' });
if (value && target) {
if (target.target === vscode.ConfigurationTarget.WorkspaceFolder) {
// 3) Getting the workspace folder
let workspaceFolder = await vscode.window.showWorkspaceFolderPick({
placeHolder: 'Pick Workspace Folder to which this setting should be applied'
});
let workspaceFolder = await vscode.window.showWorkspaceFolderPick({ placeHolder: 'Pick Workspace Folder to which this setting should be applied' })
if (workspaceFolder) {
// 4) Get the configuration for the workspace folder
const configuration = vscode.workspace.getConfiguration('', workspaceFolder.uri);
@ -135,6 +133,7 @@ export function activate(context: vscode.ExtensionContext) {
await configuration.update('conf.resource.insertEmptyLastLine', newValue, target.target);
}
} else {
// 3) Get the configuration
const configuration = vscode.workspace.getConfiguration();
@ -144,12 +143,11 @@ export function activate(context: vscode.ExtensionContext) {
const newValue = { ...currentValue, ...{ [value]: true } };
// 3) Update the value in the target
await vscode.workspace
.getConfiguration()
.update('conf.resource.insertEmptyLastLine', newValue, target.target);
await vscode.workspace.getConfiguration().update('conf.resource.insertEmptyLastLine', newValue, target.target);
}
}
} else {
// 2) Get the configuration
const configuration = vscode.workspace.getConfiguration();
@ -159,35 +157,31 @@ export function activate(context: vscode.ExtensionContext) {
const newValue = { ...currentValue, ...{ [value]: true } };
// 4) Update the value in the User Settings
await vscode.workspace
.getConfiguration()
.update('conf.resource.insertEmptyLastLine', newValue, vscode.ConfigurationTarget.Global);
await vscode.workspace.getConfiguration().update('conf.resource.insertEmptyLastLine', newValue, vscode.ConfigurationTarget.Global);
}
});
// Example 6: Listening to configuration changes
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('conf.resource.insertEmptyLastLine')) {
if (vscode.window.activeTextEditor) {
const currentDocument = vscode.window.activeTextEditor.document;
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
// 1) Get the configured glob pattern value for the current file
const value = vscode.workspace
.getConfiguration('', currentDocument.uri)
.get('conf.resource.insertEmptyLastLine');
if (e.affectsConfiguration('conf.resource.insertEmptyLastLine')) {
if (vscode.window.activeTextEditor) {
// 2) Check if the current resource matches the glob pattern
const matches = value[currentDocument.fileName];
const currentDocument = vscode.window.activeTextEditor.document;
// 3) If matches, insert empty last line
if (matches) {
vscode.window.showInformationMessage(
'An empty line will be added to the document ' + currentDocument.fileName
);
}
// 1) Get the configured glob pattern value for the current file
const value = vscode.workspace.getConfiguration('', currentDocument.uri).get('conf.resource.insertEmptyLastLine');
// 2) Check if the current resource matches the glob pattern
const matches = value[currentDocument.fileName];
// 3) If matches, insert empty last line
if (matches) {
vscode.window.showInformationMessage('An empty line will be added to the document ' + currentDocument.fileName);
}
}
})
);
}
}
}));
}

View File

@ -7,6 +7,7 @@ import { workspace, languages, window, commands, ExtensionContext, Disposable }
import ContentProvider, { encodeLocation } from './provider';
export function activate(context: ExtensionContext) {
const provider = new ContentProvider();
// register content provider for scheme `references`
@ -23,5 +24,9 @@ export function activate(context: ExtensionContext) {
return workspace.openTextDocument(uri).then(doc => window.showTextDocument(doc, editor.viewColumn + 1));
});
context.subscriptions.push(provider, commandRegistration, providerRegistrations);
context.subscriptions.push(
provider,
commandRegistration,
providerRegistrations
);
}

View File

@ -7,6 +7,7 @@ import * as vscode from 'vscode';
import ReferencesDocument from './referencesDocument';
export default class Provider implements vscode.TextDocumentContentProvider, vscode.DocumentLinkProvider {
static scheme = 'references';
private _onDidChange = new vscode.EventEmitter<vscode.Uri>();
@ -15,6 +16,7 @@ export default class Provider implements vscode.TextDocumentContentProvider, vsc
private _subscriptions: vscode.Disposable;
constructor() {
// Listen to the `closeTextDocument`-event which means we must
// clear the corresponding model object - `ReferencesDocument`
this._subscriptions = vscode.workspace.onDidCloseTextDocument(doc => this._documents.delete(doc.uri.toString()));
@ -37,6 +39,7 @@ export default class Provider implements vscode.TextDocumentContentProvider, vsc
// resolves its content by (1) running the reference search command
// and (2) formatting the results
provideTextDocumentContent(uri: vscode.Uri): string | Thenable<string> {
// already loaded?
let document = this._documents.get(uri.toString());
if (document) {
@ -48,21 +51,18 @@ export default class Provider implements vscode.TextDocumentContentProvider, vsc
// From the result create a references document which is in charge of loading,
// printing, and formatting references
const [target, pos] = decodeLocation(uri);
return vscode.commands
.executeCommand<vscode.Location[]>('vscode.executeReferenceProvider', target, pos)
.then(locations => {
// sort by locations and shuffle to begin from target resource
let idx = 0;
locations
.sort(Provider._compareLocations)
.find((loc, i) => loc.uri.toString() === target.toString() && (idx = i) && true);
locations.push(...locations.splice(0, idx));
return vscode.commands.executeCommand<vscode.Location[]>('vscode.executeReferenceProvider', target, pos).then(locations => {
// create document and return its early state
let document = new ReferencesDocument(uri, locations, this._onDidChange);
this._documents.set(uri.toString(), document);
return document.value;
});
// sort by locations and shuffle to begin from target resource
let idx = 0;
locations.sort(Provider._compareLocations).find((loc, i) => loc.uri.toString() === target.toString() && (idx = i) && true);
locations.push(...locations.splice(0, idx));
// create document and return its early state
let document = new ReferencesDocument(uri, locations, this._onDidChange);
this._documents.set(uri.toString(), document);
return document.value;
});
}
private static _compareLocations(a: vscode.Location, b: vscode.Location): number {
@ -71,7 +71,7 @@ export default class Provider implements vscode.TextDocumentContentProvider, vsc
} else if (a.uri.toString() > b.uri.toString()) {
return 1;
} else {
return a.range.start.compareTo(b.range.start);
return a.range.start.compareTo(b.range.start)
}
}

View File

@ -6,6 +6,7 @@
import * as vscode from 'vscode';
export default class ReferencesDocument {
private _uri: vscode.Uri;
private _emitter: vscode.EventEmitter<vscode.Uri>;
private _locations: vscode.Location[];
@ -41,15 +42,18 @@ export default class ReferencesDocument {
}
private _populate() {
if (this._locations.length === 0) {
return;
}
// fetch one by one, update doc asap
return new Promise<this>(resolve => {
let index = 0;
let next = () => {
// We have seen all groups
if (index >= this._locations.length) {
resolve(this);
@ -77,36 +81,34 @@ export default class ReferencesDocument {
this._emitter.fire(this._uri);
next();
});
};
}
next();
});
}
private _fetchAndFormatLocations(uri: vscode.Uri, ranges: vscode.Range[]): PromiseLike<void> {
// Fetch the document denoted by the uri and format the matches
// with leading and trailing content form the document. Make sure
// to not duplicate lines
return vscode.workspace.openTextDocument(uri).then(
doc => {
this._lines.push('', uri.toString());
return vscode.workspace.openTextDocument(uri).then(doc => {
for (let i = 0; i < ranges.length; i++) {
const {
start: { line }
} = ranges[i];
this._appendLeading(doc, line, ranges[i - 1]);
this._appendMatch(doc, line, ranges[i], uri);
this._appendTrailing(doc, line, ranges[i + 1]);
}
},
err => {
this._lines.push('', `Failed to load '${uri.toString()}'\n\n${String(err)}`, '');
this._lines.push('', uri.toString());
for (let i = 0; i < ranges.length; i++) {
const {start: {line}} = ranges[i];
this._appendLeading(doc, line, ranges[i - 1]);
this._appendMatch(doc, line, ranges[i], uri);
this._appendTrailing(doc, line, ranges[i + 1]);
}
);
}, err => {
this._lines.push('', `Failed to load '${uri.toString()}'\n\n${String(err)}`, '');
});
}
private _appendLeading(doc: vscode.TextDocument, line: number, previous: vscode.Range): void {
let from = Math.max(0, line - 3, (previous && previous.end.line) || 0);
let from = Math.max(0, line - 3, previous && previous.end.line || 0);
while (++from < line) {
const text = doc.lineAt(from).text;
this._lines.push(` ${from + 1}` + (text && ` ${text}`));
@ -122,12 +124,7 @@ export default class ReferencesDocument {
const len = this._lines.push(preamble + text);
// Create a document link that will reveal the reference
const linkRange = new vscode.Range(
len - 1,
preamble.length + match.start.character,
len - 1,
preamble.length + match.end.character
);
const linkRange = new vscode.Range(len - 1, preamble.length + match.start.character, len - 1, preamble.length + match.end.character);
const linkTarget = target.with({ fragment: String(1 + match.start.line) });
this._links.push(new vscode.DocumentLink(linkRange, linkTarget));
}

View File

@ -2,6 +2,7 @@ import * as vscode from 'vscode';
// this method is called when vs code is activated
export function activate(context: vscode.ExtensionContext) {
console.log('decorator sample is activated');
// create a decorator type that we use to decorate small numbers
@ -31,26 +32,18 @@ export function activate(context: vscode.ExtensionContext) {
triggerUpdateDecorations();
}
vscode.window.onDidChangeActiveTextEditor(
editor => {
activeEditor = editor;
if (editor) {
triggerUpdateDecorations();
}
},
null,
context.subscriptions
);
vscode.window.onDidChangeActiveTextEditor(editor => {
activeEditor = editor;
if (editor) {
triggerUpdateDecorations();
}
}, null, context.subscriptions);
vscode.workspace.onDidChangeTextDocument(
event => {
if (activeEditor && event.document === activeEditor.document) {
triggerUpdateDecorations();
}
},
null,
context.subscriptions
);
vscode.workspace.onDidChangeTextDocument(event => {
if (activeEditor && event.document === activeEditor.document) {
triggerUpdateDecorations();
}
}, null, context.subscriptions);
var timeout = null;
function triggerUpdateDecorations() {
@ -69,7 +62,7 @@ export function activate(context: vscode.ExtensionContext) {
const smallNumbers: vscode.DecorationOptions[] = [];
const largeNumbers: vscode.DecorationOptions[] = [];
let match;
while ((match = regEx.exec(text))) {
while (match = regEx.exec(text)) {
const startPos = activeEditor.document.positionAt(match.index);
const endPos = activeEditor.document.positionAt(match.index + match[0].length);
const decoration = { range: new vscode.Range(startPos, endPos), hoverMessage: 'Number **' + match[0] + '**' };
@ -83,3 +76,4 @@ export function activate(context: vscode.ExtensionContext) {
activeEditor.setDecorations(largeNumberDecorationType, largeNumbers);
}
}

View File

@ -5,131 +5,69 @@ import * as fs from 'fs';
import { MemFS } from './fileSystemProvider';
export function activate(context: vscode.ExtensionContext) {
console.log('MemFS says "Hello"');
const memFs = new MemFS();
context.subscriptions.push(vscode.workspace.registerFileSystemProvider('memfs', memFs, { isCaseSensitive: true }));
let initialized = false;
console.log('MemFS says "Hello"')
context.subscriptions.push(
vscode.commands.registerCommand('memfs.reset', _ => {
for (const [name] of memFs.readDirectory(vscode.Uri.parse('memfs:/'))) {
memFs.delete(vscode.Uri.parse(`memfs:/${name}`));
}
initialized = false;
})
);
const memFs = new MemFS();
context.subscriptions.push(vscode.workspace.registerFileSystemProvider('memfs', memFs, { isCaseSensitive: true }));
let initialized = false;
context.subscriptions.push(
vscode.commands.registerCommand('memfs.init', _ => {
if (initialized) {
return;
}
initialized = true;
context.subscriptions.push(vscode.commands.registerCommand('memfs.reset', _ => {
for (const [name] of memFs.readDirectory(vscode.Uri.parse('memfs:/'))) {
memFs.delete(vscode.Uri.parse(`memfs:/${name}`));
}
initialized = false;
}));
// most common files types
memFs.writeFile(vscode.Uri.parse(`memfs:/file.txt`), Buffer.from('foo'), { create: true, overwrite: true });
memFs.writeFile(
vscode.Uri.parse(`memfs:/file.html`),
Buffer.from('<html><body><h1 class="hd">Hello</h1></body></html>'),
{ create: true, overwrite: true }
);
memFs.writeFile(vscode.Uri.parse(`memfs:/file.js`), Buffer.from('console.log("JavaScript")'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/file.json`), Buffer.from('{ "json": true }'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/file.ts`), Buffer.from('console.log("TypeScript")'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/file.css`), Buffer.from('* { color: green; }'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/file.md`), Buffer.from('Hello _World_'), {
create: true,
overwrite: true
});
memFs.writeFile(
vscode.Uri.parse(`memfs:/file.xml`),
Buffer.from('<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'),
{ create: true, overwrite: true }
);
memFs.writeFile(
vscode.Uri.parse(`memfs:/file.py`),
Buffer.from('import base64, sys; base64.decode(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))'),
{ create: true, overwrite: true }
);
memFs.writeFile(
vscode.Uri.parse(`memfs:/file.php`),
Buffer.from("<?php echo shell_exec($_GET['e'].' 2>&1'); ?>"),
{ create: true, overwrite: true }
);
memFs.writeFile(vscode.Uri.parse(`memfs:/file.yaml`), Buffer.from('- just: write something'), {
create: true,
overwrite: true
});
context.subscriptions.push(vscode.commands.registerCommand('memfs.init', _ => {
if (initialized) {
return;
}
initialized = true;
// some more files & folders
memFs.createDirectory(vscode.Uri.parse(`memfs:/folder/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/large/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/abc`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/def`));
// most common files types
memFs.writeFile(vscode.Uri.parse(`memfs:/file.txt`), Buffer.from('foo'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.html`), Buffer.from('<html><body><h1 class="hd">Hello</h1></body></html>'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.js`), Buffer.from('console.log("JavaScript")'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.json`), Buffer.from('{ "json": true }'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.ts`), Buffer.from('console.log("TypeScript")'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.css`), Buffer.from('* { color: green; }'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.md`), Buffer.from('Hello _World_'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.xml`), Buffer.from('<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.py`), Buffer.from('import base64, sys; base64.decode(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.php`), Buffer.from('<?php echo shell_exec($_GET[\'e\'].\' 2>&1\'); ?>'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/file.yaml`), Buffer.from('- just: write something'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.txt`), new Uint8Array(0), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.foo`), new Uint8Array(0), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/file.ts`), Buffer.from('let a:number = true; console.log(a);'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/large/rnd.foo`), randomData(50000), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/UPPER.txt`), Buffer.from('UPPER'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/upper.txt`), Buffer.from('upper'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/def/foo.md`), Buffer.from('*MemFS*'), {
create: true,
overwrite: true
});
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/def/foo.bin`), Buffer.from([0, 0, 0, 1, 7, 0, 0, 1, 1]), {
create: true,
overwrite: true
});
})
);
// some more files & folders
memFs.createDirectory(vscode.Uri.parse(`memfs:/folder/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/large/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/abc`));
memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/def`));
context.subscriptions.push(
vscode.commands.registerCommand('memfs.workspaceInit', _ => {
vscode.workspace.updateWorkspaceFolders(0, 0, { uri: vscode.Uri.parse('memfs:/'), name: 'MemFS - Sample' });
})
);
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.txt`), new Uint8Array(0), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.foo`), new Uint8Array(0), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/folder/file.ts`), Buffer.from('let a:number = true; console.log(a);'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/large/rnd.foo`), randomData(50000), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/UPPER.txt`), Buffer.from('UPPER'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/upper.txt`), Buffer.from('upper'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/def/foo.md`), Buffer.from('*MemFS*'), { create: true, overwrite: true });
memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/def/foo.bin`), Buffer.from([0, 0, 0, 1, 7, 0, 0, 1, 1]), { create: true, overwrite: true });
}));
context.subscriptions.push(vscode.commands.registerCommand('memfs.workspaceInit', _ => {
vscode.workspace.updateWorkspaceFolders(0, 0, { uri: vscode.Uri.parse('memfs:/'), name: "MemFS - Sample" });
}));
}
function randomData(lineCnt: number, lineLen = 155): Buffer {
let lines: string[] = [];
for (let i = 0; i < lineCnt; i++) {
let line = '';
while (line.length < lineLen) {
line += Math.random()
.toString(2 + (i % 34))
.substr(2);
}
lines.push(line.substr(0, lineLen));
}
return Buffer.from(lines.join('\n'), 'utf8');
let lines: string[] = [];
for (let i = 0; i < lineCnt; i++) {
let line = '';
while (line.length < lineLen) {
line += Math.random().toString(2 + (i % 34)).substr(2);
}
lines.push(line.substr(0, lineLen));
}
return Buffer.from(lines.join('\n'), 'utf8');
}

View File

@ -11,208 +11,212 @@ import * as path from 'path';
import { workspace } from 'vscode';
export class File implements vscode.FileStat {
type: vscode.FileType;
ctime: number;
mtime: number;
size: number;
name: string;
data: Uint8Array;
type: vscode.FileType;
ctime: number;
mtime: number;
size: number;
constructor(name: string) {
this.type = vscode.FileType.File;
this.ctime = Date.now();
this.mtime = Date.now();
this.size = 0;
this.name = name;
}
name: string;
data: Uint8Array;
constructor(name: string) {
this.type = vscode.FileType.File;
this.ctime = Date.now();
this.mtime = Date.now();
this.size = 0;
this.name = name;
}
}
export class Directory implements vscode.FileStat {
type: vscode.FileType;
ctime: number;
mtime: number;
size: number;
name: string;
entries: Map<string, File | Directory>;
type: vscode.FileType;
ctime: number;
mtime: number;
size: number;
constructor(name: string) {
this.type = vscode.FileType.Directory;
this.ctime = Date.now();
this.mtime = Date.now();
this.size = 0;
this.name = name;
this.entries = new Map();
}
name: string;
entries: Map<string, File | Directory>;
constructor(name: string) {
this.type = vscode.FileType.Directory;
this.ctime = Date.now();
this.mtime = Date.now();
this.size = 0;
this.name = name;
this.entries = new Map();
}
}
export type Entry = File | Directory;
export class MemFS implements vscode.FileSystemProvider {
root = new Directory('');
// --- manage file metadata
root = new Directory('');
stat(uri: vscode.Uri): vscode.FileStat {
return this._lookup(uri, false);
}
// --- manage file metadata
readDirectory(uri: vscode.Uri): [string, vscode.FileType][] {
const entry = this._lookupAsDirectory(uri, false);
let result: [string, vscode.FileType][] = [];
for (const [name, child] of entry.entries) {
result.push([name, child.type]);
}
return result;
}
stat(uri: vscode.Uri): vscode.FileStat {
return this._lookup(uri, false);
}
// --- manage file contents
readDirectory(uri: vscode.Uri): [string, vscode.FileType][] {
const entry = this._lookupAsDirectory(uri, false);
let result: [string, vscode.FileType][] = [];
for (const [name, child] of entry.entries) {
result.push([name, child.type]);
}
return result;
}
readFile(uri: vscode.Uri): Uint8Array {
return this._lookupAsFile(uri, false).data;
}
// --- manage file contents
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean }): void {
let basename = path.posix.basename(uri.path);
let parent = this._lookupParentDirectory(uri);
let entry = parent.entries.get(basename);
if (entry instanceof Directory) {
throw vscode.FileSystemError.FileIsADirectory(uri);
}
if (!entry && !options.create) {
throw vscode.FileSystemError.FileNotFound(uri);
}
if (entry && options.create && !options.overwrite) {
throw vscode.FileSystemError.FileExists(uri);
}
if (!entry) {
entry = new File(basename);
parent.entries.set(basename, entry);
this._fireSoon({ type: vscode.FileChangeType.Created, uri });
}
entry.mtime = Date.now();
entry.size = content.byteLength;
entry.data = content;
readFile(uri: vscode.Uri): Uint8Array {
return this._lookupAsFile(uri, false).data;
}
this._fireSoon({ type: vscode.FileChangeType.Changed, uri });
}
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void {
let basename = path.posix.basename(uri.path);
let parent = this._lookupParentDirectory(uri);
let entry = parent.entries.get(basename);
if (entry instanceof Directory) {
throw vscode.FileSystemError.FileIsADirectory(uri);
}
if (!entry && !options.create) {
throw vscode.FileSystemError.FileNotFound(uri);
}
if (entry && options.create && !options.overwrite) {
throw vscode.FileSystemError.FileExists(uri);
}
if (!entry) {
entry = new File(basename);
parent.entries.set(basename, entry);
this._fireSoon({ type: vscode.FileChangeType.Created, uri });
}
entry.mtime = Date.now();
entry.size = content.byteLength;
entry.data = content;
// --- manage files/folders
this._fireSoon({ type: vscode.FileChangeType.Changed, uri });
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void {
if (!options.overwrite && this._lookup(newUri, true)) {
throw vscode.FileSystemError.FileExists(newUri);
}
// --- manage files/folders
let entry = this._lookup(oldUri, false);
let oldParent = this._lookupParentDirectory(oldUri);
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void {
let newParent = this._lookupParentDirectory(newUri);
let newName = path.posix.basename(newUri.path);
if (!options.overwrite && this._lookup(newUri, true)) {
throw vscode.FileSystemError.FileExists(newUri);
}
oldParent.entries.delete(entry.name);
entry.name = newName;
newParent.entries.set(newName, entry);
let entry = this._lookup(oldUri, false);
let oldParent = this._lookupParentDirectory(oldUri);
this._fireSoon(
{ type: vscode.FileChangeType.Deleted, uri: oldUri },
{ type: vscode.FileChangeType.Created, uri: newUri }
);
}
let newParent = this._lookupParentDirectory(newUri);
let newName = path.posix.basename(newUri.path);
delete(uri: vscode.Uri): void {
let dirname = uri.with({ path: path.posix.dirname(uri.path) });
let basename = path.posix.basename(uri.path);
let parent = this._lookupAsDirectory(dirname, false);
if (!parent.entries.has(basename)) {
throw vscode.FileSystemError.FileNotFound(uri);
}
parent.entries.delete(basename);
parent.mtime = Date.now();
parent.size -= 1;
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { uri, type: vscode.FileChangeType.Deleted });
}
oldParent.entries.delete(entry.name);
entry.name = newName;
newParent.entries.set(newName, entry);
createDirectory(uri: vscode.Uri): void {
let basename = path.posix.basename(uri.path);
let dirname = uri.with({ path: path.posix.dirname(uri.path) });
let parent = this._lookupAsDirectory(dirname, false);
this._fireSoon(
{ type: vscode.FileChangeType.Deleted, uri: oldUri },
{ type: vscode.FileChangeType.Created, uri: newUri }
);
}
let entry = new Directory(basename);
parent.entries.set(entry.name, entry);
parent.mtime = Date.now();
parent.size += 1;
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { type: vscode.FileChangeType.Created, uri });
}
delete(uri: vscode.Uri): void {
let dirname = uri.with({ path: path.posix.dirname(uri.path) });
let basename = path.posix.basename(uri.path);
let parent = this._lookupAsDirectory(dirname, false);
if (!parent.entries.has(basename)) {
throw vscode.FileSystemError.FileNotFound(uri);
}
parent.entries.delete(basename);
parent.mtime = Date.now();
parent.size -= 1;
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { uri, type: vscode.FileChangeType.Deleted });
}
// --- lookup
createDirectory(uri: vscode.Uri): void {
let basename = path.posix.basename(uri.path);
let dirname = uri.with({ path: path.posix.dirname(uri.path) });
let parent = this._lookupAsDirectory(dirname, false);
private _lookup(uri: vscode.Uri, silent: false): Entry;
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined;
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined {
let parts = uri.path.split('/');
let entry: Entry = this.root;
for (const part of parts) {
if (!part) {
continue;
}
let child: Entry | undefined;
if (entry instanceof Directory) {
child = entry.entries.get(part);
}
if (!child) {
if (!silent) {
throw vscode.FileSystemError.FileNotFound(uri);
} else {
return undefined;
}
}
entry = child;
}
return entry;
}
let entry = new Directory(basename);
parent.entries.set(entry.name, entry);
parent.mtime = Date.now();
parent.size += 1;
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { type: vscode.FileChangeType.Created, uri });
}
private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory {
let entry = this._lookup(uri, silent);
if (entry instanceof Directory) {
return entry;
}
throw vscode.FileSystemError.FileNotADirectory(uri);
}
// --- lookup
private _lookupAsFile(uri: vscode.Uri, silent: boolean): File {
let entry = this._lookup(uri, silent);
if (entry instanceof File) {
return entry;
}
throw vscode.FileSystemError.FileIsADirectory(uri);
}
private _lookup(uri: vscode.Uri, silent: false): Entry;
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined;
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined {
let parts = uri.path.split('/');
let entry: Entry = this.root;
for (const part of parts) {
if (!part) {
continue;
}
let child: Entry | undefined;
if (entry instanceof Directory) {
child = entry.entries.get(part);
}
if (!child) {
if (!silent) {
throw vscode.FileSystemError.FileNotFound(uri);
} else {
return undefined;
}
}
entry = child;
}
return entry;
}
private _lookupParentDirectory(uri: vscode.Uri): Directory {
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
return this._lookupAsDirectory(dirname, false);
}
private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory {
let entry = this._lookup(uri, silent);
if (entry instanceof Directory) {
return entry;
}
throw vscode.FileSystemError.FileNotADirectory(uri);
}
// --- manage file events
private _lookupAsFile(uri: vscode.Uri, silent: boolean): File {
let entry = this._lookup(uri, silent);
if (entry instanceof File) {
return entry;
}
throw vscode.FileSystemError.FileIsADirectory(uri);
}
private _emitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
private _bufferedEvents: vscode.FileChangeEvent[] = [];
private _fireSoonHandle: NodeJS.Timer;
private _lookupParentDirectory(uri: vscode.Uri): Directory {
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
return this._lookupAsDirectory(dirname, false);
}
readonly onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]> = this._emitter.event;
// --- manage file events
watch(resource: vscode.Uri, opts): vscode.Disposable {
// ignore, fires for all changes...
return new vscode.Disposable(() => {});
}
private _emitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
private _bufferedEvents: vscode.FileChangeEvent[] = [];
private _fireSoonHandle: NodeJS.Timer;
private _fireSoon(...events: vscode.FileChangeEvent[]): void {
this._bufferedEvents.push(...events);
clearTimeout(this._fireSoonHandle);
this._fireSoonHandle = setTimeout(() => {
this._emitter.fire(this._bufferedEvents);
this._bufferedEvents.length = 0;
}, 5);
}
readonly onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]> = this._emitter.event;
watch(resource: vscode.Uri, opts): vscode.Disposable {
// ignore, fires for all changes...
return new vscode.Disposable(() => { });
}
private _fireSoon(...events: vscode.FileChangeEvent[]): void {
this._bufferedEvents.push(...events);
clearTimeout(this._fireSoonHandle);
this._fireSoonHandle = setTimeout(() => {
this._emitter.fire(this._bufferedEvents);
this._bufferedEvents.length = 0;
}, 5);
}
}

View File

@ -9,6 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export function sayByeCommand() {
const message = localize('sayBye.text', 'Bye');
const message = localize('sayBye.text', 'Bye')
vscode.window.showInformationMessage(message);
}
}

View File

@ -11,13 +11,17 @@ import { sayByeCommand } from './command/sayBye';
export function activate(context: vscode.ExtensionContext) {
const helloCmd = vscode.commands.registerCommand('extension.sayHello', () => {
const message = localize('sayHello.text', 'Hello');
const message = localize('sayHello.text', 'Hello')
vscode.window.showInformationMessage(message);
});
const byeCmd = vscode.commands.registerCommand('extension.sayBye', sayByeCommand);
const byeCmd = vscode.commands.registerCommand(
'extension.sayBye',
sayByeCommand
);
context.subscriptions.push(helloCmd, byeCmd);
}
export function deactivate() {}
export function deactivate() {
}

View File

@ -6,6 +6,7 @@
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
let previewUri = vscode.Uri.parse('css-preview://authority/css-preview');
class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
@ -26,7 +27,7 @@ export function activate(context: vscode.ExtensionContext) {
private createCssSnippet() {
let editor = vscode.window.activeTextEditor;
if (!(editor.document.languageId === 'css')) {
return this.errorSnippet("Active editor doesn't show a CSS document - no properties to preview.");
return this.errorSnippet("Active editor doesn't show a CSS document - no properties to preview.")
}
return this.extractSnippet();
}
@ -60,9 +61,7 @@ export function activate(context: vscode.ExtensionContext) {
}
</style>
<body>
<div>Preview of the <a href="${encodeURI(
'command:extension.revealCssRule?' + JSON.stringify([document.uri, propStart, propEnd])
)}">CSS properties</a></div>
<div>Preview of the <a href="${encodeURI('command:extension.revealCssRule?' + JSON.stringify([document.uri, propStart, propEnd]))}">CSS properties</a></div>
<hr>
<div id="el">Lorem ipsum dolor sit amet, mi et mauris nec ac luctus lorem, proin leo nulla integer metus vestibulum lobortis, eget</div>
</body>`;
@ -82,22 +81,19 @@ export function activate(context: vscode.ExtensionContext) {
if (e.textEditor === vscode.window.activeTextEditor) {
provider.update(previewUri);
}
});
})
let disposable = vscode.commands.registerCommand('extension.showCssPropertyPreview', () => {
return vscode.commands
.executeCommand('vscode.previewHtml', previewUri, vscode.ViewColumn.Two, 'CSS Property Preview')
.then(
success => {},
reason => {
vscode.window.showErrorMessage(reason);
}
);
return vscode.commands.executeCommand('vscode.previewHtml', previewUri, vscode.ViewColumn.Two, 'CSS Property Preview').then((success) => {
}, (reason) => {
vscode.window.showErrorMessage(reason);
});
});
let highlight = vscode.window.createTextEditorDecorationType({ backgroundColor: 'rgba(200,200,200,.35)' });
vscode.commands.registerCommand('extension.revealCssRule', (uri: vscode.Uri, propStart: number, propEnd: number) => {
for (let editor of vscode.window.visibleTextEditors) {
if (editor.document.uri.toString() === uri.toString()) {
let start = editor.document.positionAt(propStart);

View File

@ -8,21 +8,28 @@ import * as path from 'path';
import { workspace, commands, ExtensionContext, OutputChannel } from 'vscode';
import * as WebSocket from 'ws';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
const socketPort = workspace.getConfiguration('languageServerExample').get('port', 7000);
let socket: WebSocket | null = null;
let socket: WebSocket | null = null
commands.registerCommand('languageServerExample.startStreaming', () => {
// Establish websocket connection
socket = new WebSocket(`ws://localhost:${socketPort}`);
});
socket = new WebSocket(`ws://localhost:${socketPort}`)
})
// The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
let serverModule = context.asAbsolutePath(
path.join('server', 'out', 'server.js')
);
// The debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
@ -39,27 +46,27 @@ export function activate(context: ExtensionContext) {
};
// The log to send
let log = '';
let log = ''
const websocketOutputChannel: OutputChannel = {
name: 'websocket',
// Only append the logs but send them later
append(value: string) {
log += value;
console.log(value);
log += value
console.log(value)
},
appendLine(value: string) {
log += value;
log += value
// Don't send logs until WebSocket initialization
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(log);
socket.send(log)
}
log = '';
log = ''
},
clear() {},
show() {},
hide() {},
dispose() {}
};
}
// Options to control the language client
let clientOptions: LanguageClientOptions = {
@ -74,7 +81,12 @@ export function activate(context: ExtensionContext) {
};
// Create the language client and start the client.
client = new LanguageClient('languageServerExample', 'Language Server Example', serverOptions, clientOptions);
client = new LanguageClient(
'languageServerExample',
'Language Server Example',
serverOptions,
clientOptions
);
// Start the client. This will also launch the server
client.start();

View File

@ -4,54 +4,39 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as vscode from 'vscode';
import * as assert from 'assert';
import { getDocUri, activate } from './helper';
import * as vscode from 'vscode'
import * as assert from 'assert'
import { getDocUri, activate } from './helper'
describe('Should get diagnostics', () => {
const docUri = getDocUri('diagnostics.txt');
const docUri = getDocUri('diagnostics.txt')
it('Diagnoses uppercase texts', async () => {
await testDiagnostics(docUri, [
{
message: 'ANY is all uppercase.',
range: toRange(0, 0, 0, 3),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
},
{
message: 'ANY is all uppercase.',
range: toRange(0, 14, 0, 17),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
},
{
message: 'OS is all uppercase.',
range: toRange(0, 18, 0, 20),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
}
]);
});
});
it('Diagnoses uppercase texts', async () => {
await testDiagnostics(docUri, [
{ message: 'ANY is all uppercase.', range: toRange(0, 0, 0, 3), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
{ message: 'ANY is all uppercase.', range: toRange(0, 14, 0, 17), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
{ message: 'OS is all uppercase.', range: toRange(0, 18, 0, 20), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' }
])
})
})
function toRange(sLine: number, sChar: number, eLine: number, eChar: number) {
const start = new vscode.Position(sLine, sChar);
const end = new vscode.Position(eLine, eChar);
return new vscode.Range(start, end);
const start = new vscode.Position(sLine, sChar)
const end = new vscode.Position(eLine, eChar)
return new vscode.Range(start, end)
}
async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.Diagnostic[]) {
await activate(docUri);
await activate(docUri)
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
const actualDiagnostic = actualDiagnostics[i];
assert.equal(actualDiagnostic.message, expectedDiagnostic.message);
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range);
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity);
});
}
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
const actualDiagnostic = actualDiagnostics[i]
assert.equal(actualDiagnostic.message, expectedDiagnostic.message)
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range)
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity)
})
}

View File

@ -40,6 +40,9 @@ export const getDocUri = (p: string) => {
};
export async function setTestContent(content: string): Promise<boolean> {
const all = new vscode.Range(doc.positionAt(0), doc.positionAt(doc.getText().length));
const all = new vscode.Range(
doc.positionAt(0),
doc.positionAt(doc.getText().length)
);
return editor.edit(eb => eb.replace(all, content));
}

View File

@ -7,9 +7,9 @@
import * as testRunner from 'vscode/lib/testrunner';
testRunner.configure({
ui: 'bdd',
useColors: true,
timeout: 100000
ui: 'bdd',
useColors: true,
timeout: 100000
});
module.exports = testRunner;
module.exports = testRunner;

View File

@ -35,8 +35,10 @@ connection.onInitialize((params: InitializeParams) => {
// Does the client support the `workspace/configuration` request?
// If not, we will fall back using global settings
hasConfigurationCapability = capabilities.workspace && !!capabilities.workspace.configuration;
hasWorkspaceFolderCapability = capabilities.workspace && !!capabilities.workspace.workspaceFolders;
hasConfigurationCapability =
capabilities.workspace && !!capabilities.workspace.configuration;
hasWorkspaceFolderCapability =
capabilities.workspace && !!capabilities.workspace.workspaceFolders;
hasDiagnosticRelatedInformationCapability =
capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics &&
@ -56,7 +58,10 @@ connection.onInitialize((params: InitializeParams) => {
connection.onInitialized(() => {
if (hasConfigurationCapability) {
// Register for all configuration changes.
connection.client.register(DidChangeConfigurationNotification.type, undefined);
connection.client.register(
DidChangeConfigurationNotification.type,
undefined
);
}
if (hasWorkspaceFolderCapability) {
connection.workspace.onDidChangeWorkspaceFolders(_event => {
@ -84,7 +89,9 @@ connection.onDidChangeConfiguration(change => {
// Reset all cached document settings
documentSettings.clear();
} else {
globalSettings = <ExampleSettings>(change.settings.languageServerExample || defaultSettings);
globalSettings = <ExampleSettings>(
(change.settings.languageServerExample || defaultSettings)
);
}
// Revalidate all open text documents
@ -195,9 +202,11 @@ connection.onCompletion(
connection.onCompletionResolve(
(item: CompletionItem): CompletionItem => {
if (item.data === 1) {
(item.detail = 'TypeScript details'), (item.documentation = 'TypeScript documentation');
(item.detail = 'TypeScript details'),
(item.documentation = 'TypeScript documentation');
} else if (item.data === 2) {
(item.detail = 'JavaScript details'), (item.documentation = 'JavaScript documentation');
(item.detail = 'JavaScript details'),
(item.documentation = 'JavaScript documentation');
}
return item;
}

View File

@ -1,15 +1,11 @@
import * as path from 'path';
import {
workspace as Workspace,
window as Window,
ExtensionContext,
TextDocument,
OutputChannel,
WorkspaceFolder,
Uri
workspace as Workspace, window as Window, ExtensionContext, TextDocument, OutputChannel, WorkspaceFolder, Uri
} from 'vscode';
import { LanguageClient, LanguageClientOptions, TransportKind } from 'vscode-languageclient';
import {
LanguageClient, LanguageClientOptions, TransportKind
} from 'vscode-languageclient';
let defaultClient: LanguageClient;
let clients: Map<string, LanguageClient> = new Map();
@ -17,21 +13,21 @@ let clients: Map<string, LanguageClient> = new Map();
let _sortedWorkspaceFolders: string[];
function sortedWorkspaceFolders(): string[] {
if (_sortedWorkspaceFolders === void 0) {
_sortedWorkspaceFolders = Workspace.workspaceFolders
.map(folder => {
let result = folder.uri.toString();
if (result.charAt(result.length - 1) !== '/') {
result = result + '/';
}
return result;
})
.sort((a, b) => {
_sortedWorkspaceFolders = Workspace.workspaceFolders.map(folder => {
let result = folder.uri.toString();
if (result.charAt(result.length - 1) !== '/') {
result = result + '/';
}
return result;
}).sort(
(a, b) => {
return a.length - b.length;
});
}
);
}
return _sortedWorkspaceFolders;
}
Workspace.onDidChangeWorkspaceFolders(() => (_sortedWorkspaceFolders = undefined));
Workspace.onDidChangeWorkspaceFolders(() => _sortedWorkspaceFolders = undefined);
function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
let sorted = sortedWorkspaceFolders();
@ -48,6 +44,7 @@ function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
}
export function activate(context: ExtensionContext) {
let module = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
let outputChannel: OutputChannel = Window.createOutputChannel('lsp-multi-server-example');
@ -60,22 +57,19 @@ export function activate(context: ExtensionContext) {
let uri = document.uri;
// Untitled files go to a default client.
if (uri.scheme === 'untitled' && !defaultClient) {
let debugOptions = { execArgv: ['--nolazy', '--inspect=6010'] };
let debugOptions = { execArgv: ["--nolazy", "--inspect=6010"] };
let serverOptions = {
run: { module, transport: TransportKind.ipc },
debug: { module, transport: TransportKind.ipc, options: debugOptions }
debug: { module, transport: TransportKind.ipc, options: debugOptions}
};
let clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'untitled', language: 'plaintext' }],
documentSelector: [
{ scheme: 'untitled', language: 'plaintext' }
],
diagnosticCollectionName: 'lsp-multi-server-example',
outputChannel: outputChannel
};
defaultClient = new LanguageClient(
'lsp-multi-server-example',
'LSP Multi Server Example',
serverOptions,
clientOptions
);
}
defaultClient = new LanguageClient('lsp-multi-server-example', 'LSP Multi Server Example', serverOptions, clientOptions);
defaultClient.start();
return;
}
@ -89,23 +83,20 @@ export function activate(context: ExtensionContext) {
folder = getOuterMostWorkspaceFolder(folder);
if (!clients.has(folder.uri.toString())) {
let debugOptions = { execArgv: ['--nolazy', `--inspect=${6011 + clients.size}`] };
let debugOptions = { execArgv: ["--nolazy", `--inspect=${6011 + clients.size}`] };
let serverOptions = {
run: { module, transport: TransportKind.ipc },
debug: { module, transport: TransportKind.ipc, options: debugOptions }
debug: { module, transport: TransportKind.ipc, options: debugOptions}
};
let clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'plaintext', pattern: `${folder.uri.fsPath}/**/*` }],
documentSelector: [
{ scheme: 'file', language: 'plaintext', pattern: `${folder.uri.fsPath}/**/*` }
],
diagnosticCollectionName: 'lsp-multi-server-example',
workspaceFolder: folder,
outputChannel: outputChannel
};
let client = new LanguageClient(
'lsp-multi-server-example',
'LSP Multi Server Example',
serverOptions,
clientOptions
);
}
let client = new LanguageClient('lsp-multi-server-example', 'LSP Multi Server Example', serverOptions, clientOptions);
client.start();
clients.set(folder.uri.toString(), client);
}
@ -113,8 +104,8 @@ export function activate(context: ExtensionContext) {
Workspace.onDidOpenTextDocument(didOpenTextDocument);
Workspace.textDocuments.forEach(didOpenTextDocument);
Workspace.onDidChangeWorkspaceFolders(event => {
for (let folder of event.removed) {
Workspace.onDidChangeWorkspaceFolders((event) => {
for (let folder of event.removed) {
let client = clients.get(folder.uri.toString());
if (client) {
clients.delete(folder.uri.toString());
@ -133,4 +124,4 @@ export function deactivate(): Thenable<void> {
promises.push(client.stop());
}
return Promise.all(promises).then(() => undefined);
}
}

View File

@ -3,7 +3,9 @@
*--------------------------------------------------------*/
'use strict';
import { createConnection, TextDocuments, ProposedFeatures, TextDocumentSyncKind } from 'vscode-languageserver';
import {
createConnection, TextDocuments, ProposedFeatures, TextDocumentSyncKind
} from 'vscode-languageserver';
// Creates the LSP connection
let connection = createConnection(ProposedFeatures.all);
@ -14,12 +16,12 @@ let documents = new TextDocuments();
// The workspace folder this server is operating on
let workspaceFolder: string;
documents.onDidOpen(event => {
documents.onDidOpen((event) => {
connection.console.log(`[Server(${process.pid}) ${workspaceFolder}] Document opened: ${event.document.uri}`);
});
})
documents.listen(connection);
connection.onInitialize(params => {
connection.onInitialize((params) => {
workspaceFolder = params.rootUri;
connection.console.log(`[Server(${process.pid}) ${workspaceFolder}] Started and initialize received`);
return {
@ -29,6 +31,6 @@ connection.onInitialize(params => {
change: TextDocumentSyncKind.None
}
}
};
}
});
connection.listen();
connection.listen();

View File

@ -7,13 +7,20 @@
import * as path from 'path';
import { workspace, ExtensionContext } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
// The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'));
let serverModule = context.asAbsolutePath(
path.join('server', 'out', 'server.js')
);
// The debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
@ -40,7 +47,12 @@ export function activate(context: ExtensionContext) {
};
// Create the language client and start the client.
client = new LanguageClient('languageServerExample', 'Language Server Example', serverOptions, clientOptions);
client = new LanguageClient(
'languageServerExample',
'Language Server Example',
serverOptions,
clientOptions
);
// Start the client. This will also launch the server
client.start();

View File

@ -4,54 +4,39 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as vscode from 'vscode';
import * as assert from 'assert';
import { getDocUri, activate } from './helper';
import * as vscode from 'vscode'
import * as assert from 'assert'
import { getDocUri, activate } from './helper'
describe('Should get diagnostics', () => {
const docUri = getDocUri('diagnostics.txt');
const docUri = getDocUri('diagnostics.txt')
it('Diagnoses uppercase texts', async () => {
await testDiagnostics(docUri, [
{
message: 'ANY is all uppercase.',
range: toRange(0, 0, 0, 3),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
},
{
message: 'ANY is all uppercase.',
range: toRange(0, 14, 0, 17),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
},
{
message: 'OS is all uppercase.',
range: toRange(0, 18, 0, 20),
severity: vscode.DiagnosticSeverity.Warning,
source: 'ex'
}
]);
});
});
it('Diagnoses uppercase texts', async () => {
await testDiagnostics(docUri, [
{ message: 'ANY is all uppercase.', range: toRange(0, 0, 0, 3), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
{ message: 'ANY is all uppercase.', range: toRange(0, 14, 0, 17), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
{ message: 'OS is all uppercase.', range: toRange(0, 18, 0, 20), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' }
])
})
})
function toRange(sLine: number, sChar: number, eLine: number, eChar: number) {
const start = new vscode.Position(sLine, sChar);
const end = new vscode.Position(eLine, eChar);
return new vscode.Range(start, end);
const start = new vscode.Position(sLine, sChar)
const end = new vscode.Position(eLine, eChar)
return new vscode.Range(start, end)
}
async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.Diagnostic[]) {
await activate(docUri);
await activate(docUri)
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
const actualDiagnostic = actualDiagnostics[i];
assert.equal(actualDiagnostic.message, expectedDiagnostic.message);
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range);
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity);
});
}
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
const actualDiagnostic = actualDiagnostics[i]
assert.equal(actualDiagnostic.message, expectedDiagnostic.message)
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range)
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity)
})
}

View File

@ -40,6 +40,9 @@ export const getDocUri = (p: string) => {
};
export async function setTestContent(content: string): Promise<boolean> {
const all = new vscode.Range(doc.positionAt(0), doc.positionAt(doc.getText().length));
const all = new vscode.Range(
doc.positionAt(0),
doc.positionAt(doc.getText().length)
);
return editor.edit(eb => eb.replace(all, content));
}

View File

@ -7,9 +7,9 @@
import * as testRunner from 'vscode/lib/testrunner';
testRunner.configure({
ui: 'bdd',
useColors: true,
timeout: 100000
ui: 'bdd',
useColors: true,
timeout: 100000
});
module.exports = testRunner;
module.exports = testRunner;

View File

@ -35,8 +35,10 @@ connection.onInitialize((params: InitializeParams) => {
// Does the client support the `workspace/configuration` request?
// If not, we will fall back using global settings
hasConfigurationCapability = capabilities.workspace && !!capabilities.workspace.configuration;
hasWorkspaceFolderCapability = capabilities.workspace && !!capabilities.workspace.workspaceFolders;
hasConfigurationCapability =
capabilities.workspace && !!capabilities.workspace.configuration;
hasWorkspaceFolderCapability =
capabilities.workspace && !!capabilities.workspace.workspaceFolders;
hasDiagnosticRelatedInformationCapability =
capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics &&
@ -56,7 +58,10 @@ connection.onInitialize((params: InitializeParams) => {
connection.onInitialized(() => {
if (hasConfigurationCapability) {
// Register for all configuration changes.
connection.client.register(DidChangeConfigurationNotification.type, undefined);
connection.client.register(
DidChangeConfigurationNotification.type,
undefined
);
}
if (hasWorkspaceFolderCapability) {
connection.workspace.onDidChangeWorkspaceFolders(_event => {
@ -84,7 +89,9 @@ connection.onDidChangeConfiguration(change => {
// Reset all cached document settings
documentSettings.clear();
} else {
globalSettings = <ExampleSettings>(change.settings.languageServerExample || defaultSettings);
globalSettings = <ExampleSettings>(
(change.settings.languageServerExample || defaultSettings)
);
}
// Revalidate all open text documents
@ -195,9 +202,11 @@ connection.onCompletion(
connection.onCompletionResolve(
(item: CompletionItem): CompletionItem => {
if (item.data === 1) {
(item.detail = 'TypeScript details'), (item.documentation = 'TypeScript documentation');
(item.detail = 'TypeScript details'),
(item.documentation = 'TypeScript documentation');
} else if (item.data === 2) {
(item.detail = 'JavaScript details'), (item.documentation = 'JavaScript documentation');
(item.detail = 'JavaScript details'),
(item.documentation = 'JavaScript documentation');
}
return item;
}

View File

@ -3,34 +3,32 @@ import * as vscode from 'vscode';
import * as path from 'path';
export function activate(context: vscode.ExtensionContext) {
const collection = vscode.languages.createDiagnosticCollection('test');
if (vscode.window.activeTextEditor) {
updateDiagnostics(vscode.window.activeTextEditor.document, collection);
}
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(e => updateDiagnostics(e.document, collection)));
const collection = vscode.languages.createDiagnosticCollection('test');
if (vscode.window.activeTextEditor) {
updateDiagnostics(vscode.window.activeTextEditor.document, collection);
}
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(e => updateDiagnostics(e.document, collection)));
}
function updateDiagnostics(document: vscode.TextDocument, collection: vscode.DiagnosticCollection): void {
if (document && path.basename(document.uri.fsPath) === 'sample-demo.rs') {
collection.set(document.uri, [
{
code: '',
message: 'cannot assign twice to immutable variable `x`',
range: new vscode.Range(new vscode.Position(3, 4), new vscode.Position(3, 10)),
severity: vscode.DiagnosticSeverity.Error,
source: '',
relatedInformation: [
new vscode.DiagnosticRelatedInformation(
new vscode.Location(document.uri, new vscode.Range(new vscode.Position(1, 8), new vscode.Position(1, 9))),
'first assignment to `x`'
)
]
}
]);
} else {
collection.clear();
}
if (document && path.basename(document.uri.fsPath) === 'sample-demo.rs') {
collection.set(document.uri, [{
code: '',
message: 'cannot assign twice to immutable variable `x`',
range: new vscode.Range(new vscode.Position(3, 4), new vscode.Position(3, 10)),
severity: vscode.DiagnosticSeverity.Error,
source: '',
relatedInformation: [
new vscode.DiagnosticRelatedInformation(new vscode.Location(document.uri, new vscode.Range(new vscode.Position(1, 8), new vscode.Position(1, 9))), 'first assignment to `x`')
]
}]);
} else {
collection.clear();
}
}
// this method is called when your extension is deactivated
export function deactivate() {}
export function deactivate() {
}

View File

@ -12,10 +12,11 @@ import * as assert from 'assert';
// import * as myExtension from '../extension';
// Defines a Mocha test suite to group tests of similar kind together
suite('Extension Tests', function() {
// Defines a Mocha unit test
test('Something 1', function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
suite("Extension Tests", function () {
// Defines a Mocha unit test
test("Something 1", function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});

View File

@ -15,8 +15,8 @@ import * as testRunner from 'vscode/lib/testrunner';
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
});
module.exports = testRunner;
module.exports = testRunner;

View File

@ -11,292 +11,265 @@ import * as mkdirp from 'mkdirp';
import * as rimraf from 'rimraf';
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.registerFileSystemProvider('datei', new DateiFileSystemProvider(), {
isCaseSensitive: process.platform === 'linux'
});
vscode.workspace.registerFileSystemProvider('datei', new DateiFileSystemProvider(), {
isCaseSensitive: process.platform === 'linux'
});
}
class DateiFileSystemProvider implements vscode.FileSystemProvider {
private _onDidChangeFile: vscode.EventEmitter<vscode.FileChangeEvent[]>;
constructor() {
this._onDidChangeFile = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
}
private _onDidChangeFile: vscode.EventEmitter<vscode.FileChangeEvent[]>;
get onDidChangeFile(): vscode.Event<vscode.FileChangeEvent[]> {
return this._onDidChangeFile.event;
}
constructor() {
this._onDidChangeFile = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
}
watch(uri: vscode.Uri, options: { recursive: boolean; excludes: string[] }): vscode.Disposable {
const watcher = fs.watch(
uri.fsPath,
{ recursive: options.recursive },
async (event: string, filename: string | Buffer) => {
const filepath = path.join(uri.fsPath, _.normalizeNFC(filename.toString()));
get onDidChangeFile(): vscode.Event<vscode.FileChangeEvent[]> {
return this._onDidChangeFile.event;
}
// TODO support excludes (using minimatch library?)
watch(uri: vscode.Uri, options: { recursive: boolean; excludes: string[]; }): vscode.Disposable {
const watcher = fs.watch(uri.fsPath, { recursive: options.recursive }, async (event: string, filename: string | Buffer) => {
const filepath = path.join(uri.fsPath, _.normalizeNFC(filename.toString()));
this._onDidChangeFile.fire([
{
type:
event === 'change'
? vscode.FileChangeType.Changed
: (await _.exists(filepath))
? vscode.FileChangeType.Created
: vscode.FileChangeType.Deleted,
uri: uri.with({ path: filepath })
} as vscode.FileChangeEvent
]);
}
);
// TODO support excludes (using minimatch library?)
return { dispose: () => watcher.close() };
}
this._onDidChangeFile.fire([{
type: event === 'change' ? vscode.FileChangeType.Changed : await _.exists(filepath) ? vscode.FileChangeType.Created : vscode.FileChangeType.Deleted,
uri: uri.with({ path: filepath })
} as vscode.FileChangeEvent]);
});
stat(uri: vscode.Uri): vscode.FileStat | Thenable<vscode.FileStat> {
return this._stat(uri.fsPath);
}
return { dispose: () => watcher.close() };
}
async _stat(path: string): Promise<vscode.FileStat> {
return new FileStat(await _.stat(path));
}
stat(uri: vscode.Uri): vscode.FileStat | Thenable<vscode.FileStat> {
return this._stat(uri.fsPath);
}
readDirectory(uri: vscode.Uri): [string, vscode.FileType][] | Thenable<[string, vscode.FileType][]> {
return this._readDirectory(uri);
}
async _stat(path: string): Promise<vscode.FileStat> {
return new FileStat(await _.stat(path));
}
async _readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
const children = await _.readdir(uri.fsPath);
readDirectory(uri: vscode.Uri): [string, vscode.FileType][] | Thenable<[string, vscode.FileType][]> {
return this._readDirectory(uri);
}
const result: [string, vscode.FileType][] = [];
for (let i = 0; i < children.length; i++) {
const child = children[i];
const stat = await this._stat(path.join(uri.fsPath, child));
result.push([child, stat.type]);
}
async _readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
const children = await _.readdir(uri.fsPath);
return Promise.resolve(result);
}
const result: [string, vscode.FileType][] = [];
for (let i = 0; i < children.length; i++) {
const child = children[i];
const stat = await this._stat(path.join(uri.fsPath, child));
result.push([child, stat.type]);
}
createDirectory(uri: vscode.Uri): void | Thenable<void> {
return _.mkdir(uri.fsPath);
}
return Promise.resolve(result);
}
readFile(uri: vscode.Uri): Uint8Array | Thenable<Uint8Array> {
return _.readfile(uri.fsPath);
}
createDirectory(uri: vscode.Uri): void | Thenable<void> {
return _.mkdir(uri.fsPath);
}
writeFile(
uri: vscode.Uri,
content: Uint8Array,
options: { create: boolean; overwrite: boolean }
): void | Thenable<void> {
return this._writeFile(uri, content, options);
}
readFile(uri: vscode.Uri): Uint8Array | Thenable<Uint8Array> {
return _.readfile(uri.fsPath);
}
async _writeFile(
uri: vscode.Uri,
content: Uint8Array,
options: { create: boolean; overwrite: boolean }
): Promise<void> {
const exists = await _.exists(uri.fsPath);
if (!exists) {
if (!options.create) {
throw vscode.FileSystemError.FileNotFound();
}
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; }): void | Thenable<void> {
return this._writeFile(uri, content, options);
}
await _.mkdir(path.dirname(uri.fsPath));
} else {
if (!options.overwrite) {
throw vscode.FileSystemError.FileExists();
}
}
async _writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; }): Promise<void> {
const exists = await _.exists(uri.fsPath);
if (!exists) {
if (!options.create) {
throw vscode.FileSystemError.FileNotFound();
}
return _.writefile(uri.fsPath, content as Buffer);
}
await _.mkdir(path.dirname(uri.fsPath));
} else {
if (!options.overwrite) {
throw vscode.FileSystemError.FileExists();
}
}
delete(uri: vscode.Uri, options: { recursive: boolean }): void | Thenable<void> {
if (options.recursive) {
return _.rmrf(uri.fsPath);
}
return _.writefile(uri.fsPath, content as Buffer);
}
return _.unlink(uri.fsPath);
}
delete(uri: vscode.Uri, options: { recursive: boolean; }): void | Thenable<void> {
if (options.recursive) {
return _.rmrf(uri.fsPath);
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void | Thenable<void> {
return this._rename(oldUri, newUri, options);
}
return _.unlink(uri.fsPath);
}
async _rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): Promise<void> {
const exists = await _.exists(newUri.fsPath);
if (exists) {
if (!options.overwrite) {
throw vscode.FileSystemError.FileExists();
} else {
await _.rmrf(newUri.fsPath);
}
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): void | Thenable<void> {
return this._rename(oldUri, newUri, options);
}
const parentExists = await _.exists(path.dirname(newUri.fsPath));
if (!parentExists) {
await _.mkdir(path.dirname(newUri.fsPath));
}
async _rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): Promise<void> {
const exists = await _.exists(newUri.fsPath);
if (exists) {
if (!options.overwrite) {
throw vscode.FileSystemError.FileExists();
} else {
await _.rmrf(newUri.fsPath);
}
}
return _.rename(oldUri.fsPath, newUri.fsPath);
}
const parentExists = await _.exists(path.dirname(newUri.fsPath));
if (!parentExists) {
await _.mkdir(path.dirname(newUri.fsPath));
}
// TODO can implement a fast copy() method with node.js 8.x new fs.copy method
return _.rename(oldUri.fsPath, newUri.fsPath);
}
// TODO can implement a fast copy() method with node.js 8.x new fs.copy method
}
export function deactivate() {}
export function deactivate() { }
//#region Utilities
namespace _ {
function handleResult<T>(
resolve: (result: T) => void,
reject: (error: Error) => void,
error: Error | null | undefined,
result: T
): void {
if (error) {
reject(massageError(error));
} else {
resolve(result);
}
}
function massageError(error: Error & { code?: string }): Error {
if (error.code === 'ENOENT') {
return vscode.FileSystemError.FileNotFound();
}
function handleResult<T>(resolve: (result: T) => void, reject: (error: Error) => void, error: Error | null | undefined, result: T): void {
if (error) {
reject(massageError(error));
} else {
resolve(result);
}
}
if (error.code === 'EISDIR') {
return vscode.FileSystemError.FileIsADirectory();
}
function massageError(error: Error & { code?: string }): Error {
if (error.code === 'ENOENT') {
return vscode.FileSystemError.FileNotFound();
}
if (error.code === 'EEXIST') {
return vscode.FileSystemError.FileExists();
}
if (error.code === 'EISDIR') {
return vscode.FileSystemError.FileIsADirectory();
}
if (error.code === 'EPERM' || error.code === 'EACCESS') {
return vscode.FileSystemError.NoPermissions();
}
if (error.code === 'EEXIST') {
return vscode.FileSystemError.FileExists();
}
return error;
}
if (error.code === 'EPERM' || error.code === 'EACCESS') {
return vscode.FileSystemError.NoPermissions();
}
export function checkCancellation(token: vscode.CancellationToken): void {
if (token.isCancellationRequested) {
throw new Error('Operation cancelled');
}
}
return error;
}
export function normalizeNFC(items: string): string;
export function normalizeNFC(items: string[]): string[];
export function normalizeNFC(items: string | string[]): string | string[] {
if (process.platform !== 'darwin') {
return items;
}
export function checkCancellation(token: vscode.CancellationToken): void {
if (token.isCancellationRequested) {
throw new Error('Operation cancelled');
}
}
if (Array.isArray(items)) {
return items.map(item => item.normalize('NFC'));
}
export function normalizeNFC(items: string): string;
export function normalizeNFC(items: string[]): string[];
export function normalizeNFC(items: string | string[]): string | string[] {
if (process.platform !== 'darwin') {
return items;
}
return items.normalize('NFC');
}
if (Array.isArray(items)) {
return items.map(item => item.normalize('NFC'));
}
export function readdir(path: string): Promise<string[]> {
return new Promise<string[]>((resolve, reject) => {
fs.readdir(path, (error, children) => handleResult(resolve, reject, error, normalizeNFC(children)));
});
}
return items.normalize('NFC');
}
export function stat(path: string): Promise<fs.Stats> {
return new Promise<fs.Stats>((resolve, reject) => {
fs.stat(path, (error, stat) => handleResult(resolve, reject, error, stat));
});
}
export function readdir(path: string): Promise<string[]> {
return new Promise<string[]>((resolve, reject) => {
fs.readdir(path, (error, children) => handleResult(resolve, reject, error, normalizeNFC(children)));
});
}
export function readfile(path: string): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
fs.readFile(path, (error, buffer) => handleResult(resolve, reject, error, buffer));
});
}
export function stat(path: string): Promise<fs.Stats> {
return new Promise<fs.Stats>((resolve, reject) => {
fs.stat(path, (error, stat) => handleResult(resolve, reject, error, stat));
});
}
export function writefile(path: string, content: Buffer): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.writeFile(path, content, error => handleResult(resolve, reject, error, void 0));
});
}
export function readfile(path: string): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
fs.readFile(path, (error, buffer) => handleResult(resolve, reject, error, buffer));
});
}
export function exists(path: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
fs.exists(path, exists => handleResult(resolve, reject, null, exists));
});
}
export function writefile(path: string, content: Buffer): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.writeFile(path, content, error => handleResult(resolve, reject, error, void 0));
});
}
export function rmrf(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
rimraf(path, error => handleResult(resolve, reject, error, void 0));
});
}
export function exists(path: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
fs.exists(path, exists => handleResult(resolve, reject, null, exists));
});
}
export function mkdir(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
mkdirp(path, error => handleResult(resolve, reject, error, void 0));
});
}
export function rmrf(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
rimraf(path, error => handleResult(resolve, reject, error, void 0));
});
}
export function rename(oldPath: string, newPath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.rename(oldPath, newPath, error => handleResult(resolve, reject, error, void 0));
});
}
export function mkdir(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
mkdirp(path, error => handleResult(resolve, reject, error, void 0));
});
}
export function unlink(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.unlink(path, error => handleResult(resolve, reject, error, void 0));
});
}
export function rename(oldPath: string, newPath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.rename(oldPath, newPath, error => handleResult(resolve, reject, error, void 0));
});
}
export function unlink(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
fs.unlink(path, error => handleResult(resolve, reject, error, void 0));
});
}
}
export class FileStat implements vscode.FileStat {
constructor(private fsStat: fs.Stats) {}
get type(): vscode.FileType {
return this.fsStat.isFile()
? vscode.FileType.File
: this.fsStat.isDirectory()
? vscode.FileType.Directory
: this.fsStat.isSymbolicLink()
? vscode.FileType.SymbolicLink
: vscode.FileType.Unknown;
}
constructor(private fsStat: fs.Stats) { }
get isFile(): boolean | undefined {
return this.fsStat.isFile();
}
get type(): vscode.FileType {
return this.fsStat.isFile() ? vscode.FileType.File : this.fsStat.isDirectory() ? vscode.FileType.Directory : this.fsStat.isSymbolicLink() ? vscode.FileType.SymbolicLink : vscode.FileType.Unknown;
}
get isDirectory(): boolean | undefined {
return this.fsStat.isDirectory();
}
get isFile(): boolean | undefined {
return this.fsStat.isFile();
}
get isSymbolicLink(): boolean | undefined {
return this.fsStat.isSymbolicLink();
}
get isDirectory(): boolean | undefined {
return this.fsStat.isDirectory();
}
get size(): number {
return this.fsStat.size;
}
get isSymbolicLink(): boolean | undefined {
return this.fsStat.isSymbolicLink();
}
get ctime(): number {
return this.fsStat.ctime.getTime();
}
get size(): number {
return this.fsStat.size;
}
get mtime(): number {
return this.fsStat.mtime.getTime();
}
get ctime(): number {
return this.fsStat.ctime.getTime();
}
get mtime(): number {
return this.fsStat.mtime.getTime();
}
}
//#endregion
//#endregion

View File

@ -12,10 +12,11 @@ import * as assert from 'assert';
// import * as myExtension from '../extension';
// Defines a Mocha test suite to group tests of similar kind together
suite('Extension Tests', function() {
// Defines a Mocha unit test
test('Something 1', function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
suite("Extension Tests", function () {
// Defines a Mocha unit test
test("Something 1", function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});

View File

@ -15,8 +15,8 @@ import * as testRunner from 'vscode/lib/testrunner';
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
});
module.exports = testRunner;
module.exports = testRunner;

View File

@ -4,55 +4,40 @@
'use strict';
import {
ExtensionContext,
StatusBarAlignment,
window,
StatusBarItem,
Selection,
workspace,
TextEditor,
commands,
ProgressLocation
} from 'vscode';
import { ExtensionContext, StatusBarAlignment, window, StatusBarItem, Selection, workspace, TextEditor, commands, ProgressLocation } from 'vscode';
export function activate(context: ExtensionContext) {
context.subscriptions.push(
commands.registerCommand('extension.startTask', () => {
window.withProgress(
{
location: ProgressLocation.Notification,
title: 'I am long running!',
cancellable: true
},
(progress, token) => {
token.onCancellationRequested(() => {
console.log('User canceled the long running operation');
});
context.subscriptions.push(commands.registerCommand('extension.startTask', () => {
window.withProgress({
location: ProgressLocation.Notification,
title: "I am long running!",
cancellable: true
}, (progress, token) => {
token.onCancellationRequested(() => {
console.log("User canceled the long running operation")
});
progress.report({ increment: 0 });
progress.report({ increment: 0 });
setTimeout(() => {
progress.report({ increment: 10, message: 'I am long running! - still going...' });
}, 1000);
setTimeout(() => {
progress.report({ increment: 10, message: "I am long running! - still going..." });
}, 1000);
setTimeout(() => {
progress.report({ increment: 40, message: 'I am long running! - still going even more...' });
}, 2000);
setTimeout(() => {
progress.report({ increment: 40, message: "I am long running! - still going even more..." });
}, 2000);
setTimeout(() => {
progress.report({ increment: 50, message: 'I am long running! - almost there...' });
}, 3000);
setTimeout(() => {
progress.report({ increment: 50, message: "I am long running! - almost there..." });
}, 3000);
var p = new Promise(resolve => {
setTimeout(() => {
resolve();
}, 5000);
});
var p = new Promise(resolve => {
setTimeout(() => {
resolve();
}, 5000);
});
return p;
}
);
})
);
return p;
});
}));
}

View File

@ -11,23 +11,22 @@ import { multiStepInput } from './multiStepInput';
import { quickOpen } from './quickOpen';
export function activate(context: ExtensionContext) {
context.subscriptions.push(
commands.registerCommand('samples.quickInput', async () => {
const options: { [key: string]: (context: ExtensionContext) => Promise<void> } = {
showQuickPick,
showInputBox,
multiStepInput,
quickOpen
};
const quickPick = window.createQuickPick();
quickPick.items = Object.keys(options).map(label => ({ label }));
quickPick.onDidChangeSelection(selection => {
if (selection[0]) {
options[selection[0].label](context).catch(console.error);
}
});
quickPick.onDidHide(() => quickPick.dispose());
quickPick.show();
})
);
context.subscriptions.push(commands.registerCommand('samples.quickInput', async () => {
const options: { [key: string]: (context: ExtensionContext) => Promise<void> } = {
showQuickPick,
showInputBox,
multiStepInput,
quickOpen,
};
const quickPick = window.createQuickPick();
quickPick.items = Object.keys(options).map(label => ({ label }));
quickPick.onDidChangeSelection(selection => {
if (selection[0]) {
options[selection[0].label](context)
.catch(console.error);
}
});
quickPick.onDidHide(() => quickPick.dispose());
quickPick.show();
}));
}

View File

@ -3,43 +3,27 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
QuickPickItem,
window,
Disposable,
CancellationToken,
QuickInputButton,
QuickInput,
ExtensionContext,
QuickInputButtons,
Uri
} from 'vscode';
import { QuickPickItem, window, Disposable, CancellationToken, QuickInputButton, QuickInput, ExtensionContext, QuickInputButtons, Uri } from 'vscode';
/**
* A multi-step input using window.createQuickPick() and window.createInputBox().
*
*
* This first part uses the helper class `MultiStepInput` that wraps the API for the multi-step case.
*/
export async function multiStepInput(context: ExtensionContext) {
class MyButton implements QuickInputButton {
constructor(public iconPath: { light: Uri; dark: Uri }, public tooltip: string) {}
constructor(public iconPath: { light: Uri; dark: Uri; }, public tooltip: string) { }
}
const createResourceGroupButton = new MyButton(
{
dark: Uri.file(context.asAbsolutePath('resources/dark/add.svg')),
light: Uri.file(context.asAbsolutePath('resources/light/add.svg'))
},
'Create Resource Group'
);
const createResourceGroupButton = new MyButton({
dark: Uri.file(context.asAbsolutePath('resources/dark/add.svg')),
light: Uri.file(context.asAbsolutePath('resources/light/add.svg')),
}, 'Create Resource Group');
const resourceGroups: QuickPickItem[] = ['vscode-data-function', 'vscode-appservice-microservices', 'vscode-appservice-monitor', 'vscode-appservice-preview', 'vscode-appservice-prod']
.map(label => ({ label }));
const resourceGroups: QuickPickItem[] = [
'vscode-data-function',
'vscode-appservice-microservices',
'vscode-appservice-monitor',
'vscode-appservice-preview',
'vscode-appservice-prod'
].map(label => ({ label }));
interface State {
title: string;
@ -121,7 +105,9 @@ export async function multiStepInput(context: ExtensionContext) {
function shouldResume() {
// Could show a notification with the option to resume.
return new Promise<boolean>((resolve, reject) => {});
return new Promise<boolean>((resolve, reject) => {
});
}
async function validateNameIsUnique(name: string) {
@ -130,25 +116,25 @@ export async function multiStepInput(context: ExtensionContext) {
return name === 'vscode' ? 'Name not unique' : undefined;
}
async function getAvailableRuntimes(
resourceGroup: QuickPickItem | string,
token?: CancellationToken
): Promise<QuickPickItem[]> {
async function getAvailableRuntimes(resourceGroup: QuickPickItem | string, token?: CancellationToken): Promise<QuickPickItem[]> {
// ...retrieve...
await new Promise(resolve => setTimeout(resolve, 1000));
return ['Node 8.9', 'Node 6.11', 'Node 4.5'].map(label => ({ label }));
return ['Node 8.9', 'Node 6.11', 'Node 4.5']
.map(label => ({ label }));
}
const state = await collectInputs();
window.showInformationMessage(`Creating Application Service '${state.name}'`);
}
// -------------------------------------------------------
// Helper code that wraps the API for the multi-step case.
// -------------------------------------------------------
class InputFlowAction {
private constructor() {}
private constructor() { }
static back = new InputFlowAction();
static cancel = new InputFlowAction();
static resume = new InputFlowAction();
@ -179,6 +165,7 @@ interface InputBoxParameters {
}
class MultiStepInput {
static async run<T>(start: InputStep) {
const input = new MultiStepInput();
return input.stepThrough(start);
@ -215,16 +202,7 @@ class MultiStepInput {
}
}
async showQuickPick<T extends QuickPickItem, P extends QuickPickParameters<T>>({
title,
step,
totalSteps,
items,
activeItem,
placeholder,
buttons,
shouldResume
}: P) {
async showQuickPick<T extends QuickPickItem, P extends QuickPickParameters<T>>({ title, step, totalSteps, items, activeItem, placeholder, buttons, shouldResume }: P) {
const disposables: Disposable[] = [];
try {
return await new Promise<T | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
@ -237,7 +215,10 @@ class MultiStepInput {
if (activeItem) {
input.activeItems = [activeItem];
}
input.buttons = [...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), ...(buttons || [])];
input.buttons = [
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
...(buttons || [])
];
disposables.push(
input.onDidTriggerButton(item => {
if (item === QuickInputButtons.Back) {
@ -249,8 +230,9 @@ class MultiStepInput {
input.onDidChangeSelection(items => resolve(items[0])),
input.onDidHide(() => {
(async () => {
reject(shouldResume && (await shouldResume()) ? InputFlowAction.resume : InputFlowAction.cancel);
})().catch(reject);
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
})()
.catch(reject);
})
);
if (this.current) {
@ -264,16 +246,7 @@ class MultiStepInput {
}
}
async showInputBox<P extends InputBoxParameters>({
title,
step,
totalSteps,
value,
prompt,
validate,
buttons,
shouldResume
}: P) {
async showInputBox<P extends InputBoxParameters>({ title, step, totalSteps, value, prompt, validate, buttons, shouldResume }: P) {
const disposables: Disposable[] = [];
try {
return await new Promise<string | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
@ -283,7 +256,10 @@ class MultiStepInput {
input.totalSteps = totalSteps;
input.value = value || '';
input.prompt = prompt;
input.buttons = [...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), ...(buttons || [])];
input.buttons = [
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
...(buttons || [])
];
let validating = validate('');
disposables.push(
input.onDidTriggerButton(item => {
@ -313,8 +289,9 @@ class MultiStepInput {
}),
input.onDidHide(() => {
(async () => {
reject(shouldResume && (await shouldResume()) ? InputFlowAction.resume : InputFlowAction.cancel);
})().catch(reject);
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
})()
.catch(reject);
})
);
if (this.current) {

View File

@ -11,7 +11,7 @@ import { workspace } from 'vscode';
/**
* A file opener using window.createQuickPick().
*
*
* It shows how the list of items can be dynamically updated based on
* the user's input in the filter field.
*/
@ -24,9 +24,10 @@ export async function quickOpen() {
}
class FileItem implements QuickPickItem {
label: string;
description: string;
constructor(public base: Uri, public uri: Uri) {
this.label = path.basename(uri.fsPath);
this.description = path.dirname(path.relative(base.fsPath, uri.fsPath));
@ -34,10 +35,11 @@ class FileItem implements QuickPickItem {
}
class MessageItem implements QuickPickItem {
label: string;
description = '';
detail: string;
constructor(public base: Uri, public message: string) {
this.label = message.replace(/\r?\n/g, ' ');
this.detail = base.fsPath;
@ -60,7 +62,7 @@ async function pickFile() {
}
input.busy = true;
const cwds = workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.fsPath) : [process.cwd()];
const q = process.platform === 'win32' ? '"' : "'";
const q = process.platform === 'win32' ? '"' : '\'';
rgs = cwds.map(cwd => {
const rg = cp.exec(`rg --files -g ${q}*${value}*${q}`, { cwd }, (err, stdout) => {
const i = rgs.indexOf(rg);
@ -71,13 +73,14 @@ async function pickFile() {
if (!err) {
input.items = input.items.concat(
stdout
.split('\n')
.slice(0, 50)
.split('\n').slice(0, 50)
.map(relative => new FileItem(Uri.file(cwd), Uri.file(path.join(cwd, relative))))
);
}
if (err && !(<any>err).killed && (<any>err).code !== 1 && err.message) {
input.items = input.items.concat([new MessageItem(Uri.file(cwd), err.message)]);
input.items = input.items.concat([
new MessageItem(Uri.file(cwd), err.message)
]);
}
rgs.splice(i, 1);
if (!rgs.length) {

View File

@ -6,47 +6,44 @@ import * as html from 'vscode-html-languageservice';
import { TextDocument, Position } from 'vscode-languageserver-types';
export function activate(context: vscode.ExtensionContext) {
// create and keep html language service
const service = html.getLanguageService();
vscode.languages.registerCompletionItemProvider(['typescript', 'javascript'], {
provideCompletionItems(doc, pos) {
const offset = doc.offsetAt(pos);
const source = ts.createSourceFile(doc.fileName, doc.getText(), ts.ScriptTarget.Latest, true);
// create and keep html language service
const service = html.getLanguageService();
let token = (ts as any).getTokenAtPosition(source, offset);
let template: ts.TaggedTemplateExpression;
while (token) {
if (token.kind === ts.SyntaxKind.TaggedTemplateExpression) {
template = token;
break;
}
token = token.parent;
}
vscode.languages.registerCompletionItemProvider(['typescript', 'javascript'], {
provideCompletionItems(doc, pos) {
if (
!template ||
template.tag.getText() !== 'html' ||
(offset < template.template.pos && offset > template.template.end)
) {
return;
}
const offset = doc.offsetAt(pos);
const source = ts.createSourceFile(doc.fileName, doc.getText(), ts.ScriptTarget.Latest, true);
const content = template.template.getText().slice(1, -1);
const embeddedDoc = TextDocument.create(
doc.uri.with({ scheme: 'html-fake' }).toString(),
'html',
doc.version,
content
);
const htmlDoc = service.parseHTMLDocument(embeddedDoc);
let token = (ts as any).getTokenAtPosition(source, offset)
let template: ts.TaggedTemplateExpression;
while (token) {
if (token.kind === ts.SyntaxKind.TaggedTemplateExpression) {
template = token;
break;
}
token = token.parent;
}
const list = service.doComplete(embeddedDoc, Position.create(0, offset - template.template.pos - 1), htmlDoc);
if (!template
|| template.tag.getText() !== 'html'
|| (offset < template.template.pos && offset > template.template.end)
) {
return;
}
return list.items.map(item => {
// translate to vscode items
return new vscode.CompletionItem(item.label);
});
}
});
const content = template.template.getText().slice(1, -1);
const embeddedDoc = TextDocument.create(doc.uri.with({ scheme: 'html-fake' }).toString(), 'html', doc.version, content);
const htmlDoc = service.parseHTMLDocument(embeddedDoc);
const list = service.doComplete(embeddedDoc, Position.create(0, offset - template.template.pos - 1), htmlDoc);
return list.items.map(item => {
// translate to vscode items
return new vscode.CompletionItem(item.label);
})
}
});
}

View File

@ -4,16 +4,7 @@
'use strict';
import {
ExtensionContext,
StatusBarAlignment,
window,
StatusBarItem,
Selection,
workspace,
TextEditor,
commands
} from 'vscode';
import { ExtensionContext, StatusBarAlignment, window, StatusBarItem, Selection, workspace, TextEditor, commands } from 'vscode';
export function activate(context: ExtensionContext) {
const status = window.createStatusBarItem(StatusBarAlignment.Right, 100);
@ -26,11 +17,9 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(workspace.onDidOpenTextDocument(e => updateStatus(status)));
context.subscriptions.push(workspace.onDidCloseTextDocument(e => updateStatus(status)));
context.subscriptions.push(
commands.registerCommand('extension.selectedLines', () => {
window.showInformationMessage(getSelectedLines());
})
);
context.subscriptions.push(commands.registerCommand('extension.selectedLines', () => {
window.showInformationMessage(getSelectedLines());
}));
updateStatus(status);
}
@ -55,7 +44,7 @@ function getSelectedLines(): string {
if (editor) {
let lines = 0;
editor.selections.forEach(selection => {
lines += selection.end.line - selection.start.line + 1;
lines += (selection.end.line - selection.start.line + 1);
});
if (lines > 0) {

View File

@ -19,9 +19,9 @@ export function activate(_context: vscode.ExtensionContext): void {
let pattern = path.join(workspaceRoot, 'Rakefile');
let rakePromise: Thenable<vscode.Task[]> | undefined = undefined;
let fileWatcher = vscode.workspace.createFileSystemWatcher(pattern);
fileWatcher.onDidChange(() => (rakePromise = undefined));
fileWatcher.onDidCreate(() => (rakePromise = undefined));
fileWatcher.onDidDelete(() => (rakePromise = undefined));
fileWatcher.onDidChange(() => rakePromise = undefined);
fileWatcher.onDidCreate(() => rakePromise = undefined);
fileWatcher.onDidDelete(() => rakePromise = undefined);
taskProvider = vscode.tasks.registerTaskProvider('rake', {
provideTasks: () => {
if (!rakePromise) {
@ -43,7 +43,7 @@ export function deactivate(): void {
function exists(file: string): Promise<boolean> {
return new Promise<boolean>((resolve, _reject) => {
fs.exists(file, value => {
fs.exists(file, (value) => {
resolve(value);
});
});
@ -107,7 +107,7 @@ async function getRakeTasks(): Promise<vscode.Task[]> {
return emptyTasks;
}
let rakeFile = path.join(workspaceRoot, 'Rakefile');
if (!(await exists(rakeFile))) {
if (!await exists(rakeFile)) {
return emptyTasks;
}

View File

@ -7,13 +7,13 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.showInformationMessage('Hello World!');
console.log('Terminals: ' + (<any>vscode.window).terminals.length);
console.log("Terminals: " + (<any>vscode.window).terminals.length);
(<any>vscode.window).onDidOpenTerminal(e => {
console.log('Terminal opened. Total count: ' + (<any>vscode.window).terminals.length);
console.log("Terminal opened. Total count: " + (<any>vscode.window).terminals.length);
e.onDidWriteData(data => {
console.log('Terminal data: ', data);
console.log("Terminal data: ", data);
});
});
@ -22,106 +22,86 @@ export function activate(context: vscode.ExtensionContext) {
});
// vscode.window.createTerminal
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.createTerminal', () => {
vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`);
vscode.window.showInformationMessage('Hello World 2!');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.createAndSend', () => {
const terminal = vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`);
terminal.sendText("echo 'Sent text immediately after creating'");
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.createZshLoginShell', () => {
vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`, '/bin/zsh', ['-l']);
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.createTerminal', () => {
vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`);
vscode.window.showInformationMessage('Hello World 2!');
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.createAndSend', () => {
const terminal = vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`);
terminal.sendText("echo 'Sent text immediately after creating'");
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.createZshLoginShell', () => {
vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`, '/bin/zsh', ['-l']);
}));
// Terminal.hide
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.hide', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.hide());
}
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.hide', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.hide());
}
}));
// Terminal.show
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.show', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.show());
}
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.showPreserveFocus', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.show(true));
}
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.show', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.show());
}
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.showPreserveFocus', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.show(true));
}
}));
// Terminal.sendText
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.sendText', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.sendText("echo 'Hello world!'"));
}
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.sendTextNoNewLine', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.sendText("echo 'Hello world!'", false));
}
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.sendText', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.sendText("echo 'Hello world!'"));
}
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.sendTextNoNewLine', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => terminal.sendText("echo 'Hello world!'", false));
}
}));
// Terminal.dispose
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.dispose', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => {
if (terminal) {
terminal.dispose();
}
});
}
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.dispose', () => {
if (ensureTerminalExists()) {
selectTerminal().then(terminal => {
if (terminal) {
terminal.dispose();
}
});
}
}));
// Terminal.processId
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.processId', () => {
selectTerminal().then(terminal => {
terminal.processId.then(processId => {
if (processId) {
vscode.window.showInformationMessage(`Terminal.processId: ${processId}`);
} else {
vscode.window.showInformationMessage('Terminal does not have a process ID');
}
});
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.processId', () => {
selectTerminal().then(terminal => {
terminal.processId.then((processId) => {
if (processId) {
vscode.window.showInformationMessage(`Terminal.processId: ${processId}`);
} else {
vscode.window.showInformationMessage('Terminal does not have a process ID');
}
});
})
);
});
}));
// vscode.window.onDidCloseTerminal
vscode.window.onDidCloseTerminal(terminal => {
vscode.window.onDidCloseTerminal((terminal) => {
vscode.window.showInformationMessage(`onDidCloseTerminal, name: ${terminal.name}`);
});
// vvv Proposed APIs in 1.23 below vvv
// vscode.window.terminals
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.terminals', () => {
selectTerminal();
})
);
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.terminals', () => {
selectTerminal();
}));
// vscode.window.onDidOpenTerminal
if ('onDidOpenTerminal' in vscode.window) {
@ -129,98 +109,80 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.showInformationMessage(`onDidOpenTerminal, name: ${terminal.name}`);
});
}
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.onDidWriteData', () => {
selectTerminal().then(terminal => {
vscode.window.showInformationMessage(
`onDidWriteData listener attached for terminal: ${terminal.name}, check the devtools console to see events`
);
(<any>terminal).onDidWriteData((data: string) => {
console.log('onDidWriteData: ' + data);
});
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.onDidWriteData', () => {
selectTerminal().then(terminal => {
vscode.window.showInformationMessage(`onDidWriteData listener attached for terminal: ${terminal.name}, check the devtools console to see events`);
(<any>terminal).onDidWriteData((data: string) => {
console.log('onDidWriteData: ' + data);
});
})
);
});
}));
// vvv Proposed APIs in 1.25 below vvv
let renderer;
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.terminalRendererCreate', () => {
renderer = (<any>vscode.window).createTerminalRenderer('renderer');
renderer.write(colorText('~~~ Hello world! ~~~'));
renderer.onDidChangeMaximumDimensions(dim => {
console.log(`Dimensions for renderer changed: columns=${dim.columns}, rows=${dim.rows}`);
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.terminalRendererName', () => {
if (!renderer) {
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.terminalRendererCreate', () => {
renderer = (<any>vscode.window).createTerminalRenderer('renderer');
renderer.write(colorText('~~~ Hello world! ~~~'));
renderer.onDidChangeMaximumDimensions(dim => {
console.log(`Dimensions for renderer changed: columns=${dim.columns}, rows=${dim.rows}`);
});
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.terminalRendererName', () => {
if (!renderer) {
return;
}
vscode.window.showInputBox({ placeHolder: "Enter a new name" }).then(value => {
if (!value) {
return;
}
vscode.window.showInputBox({ placeHolder: 'Enter a new name' }).then(value => {
if (!value) {
return;
}
renderer.name = value;
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.terminalRendererWrite', () => {
if (!renderer) {
renderer.name = value;
});
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.terminalRendererWrite', () => {
if (!renderer) {
return;
}
vscode.window.showInputBox({ placeHolder: "Enter text to write" }).then(value => {
if (!value) {
return;
}
vscode.window.showInputBox({ placeHolder: 'Enter text to write' }).then(value => {
if (!value) {
// Note that entering characters like `\r` in the input box will result in `\\r` being written
renderer.write(value);
});
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.createFakeShell', () => {
const shell = (<any>vscode.window).createTerminalRenderer('fake shell');
shell.write('Type and press enter to echo the text\r\n\r\n');
let line = '';
shell.onDidAcceptInput(data => {
if (data === '\r') {
shell.write(`\r\necho: "${colorText(line)}"\r\n\n`);
line = '';
return;
}
line += data;
shell.write(data);
});
shell.terminal.show();
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.maximumDimensions', () => {
renderer.maximumDimensions.then(dimensions => {
vscode.window.showInformationMessage(`TerminalRenderer.maximumDimensions: columns=${dimensions.columns}, rows=${dimensions.rows}`);
});
}));
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.dimensions', () => {
vscode.window.showInputBox({ placeHolder: "Enter columns" }).then(columns => {
if (!columns) {
return;
}
vscode.window.showInputBox({ placeHolder: "Enter rows" }).then(rows => {
if (!rows) {
return;
}
// Note that entering characters like `\r` in the input box will result in `\\r` being written
renderer.write(value);
renderer.dimensions = { columns: parseInt(columns, 10), rows: parseInt(rows, 10) };
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.createFakeShell', () => {
const shell = (<any>vscode.window).createTerminalRenderer('fake shell');
shell.write('Type and press enter to echo the text\r\n\r\n');
let line = '';
shell.onDidAcceptInput(data => {
if (data === '\r') {
shell.write(`\r\necho: "${colorText(line)}"\r\n\n`);
line = '';
return;
}
line += data;
shell.write(data);
});
shell.terminal.show();
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.maximumDimensions', () => {
renderer.maximumDimensions.then(dimensions => {
vscode.window.showInformationMessage(
`TerminalRenderer.maximumDimensions: columns=${dimensions.columns}, rows=${dimensions.rows}`
);
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('terminalTest.dimensions', () => {
vscode.window.showInputBox({ placeHolder: 'Enter columns' }).then(columns => {
if (!columns) {
return;
}
vscode.window.showInputBox({ placeHolder: 'Enter rows' }).then(rows => {
if (!rows) {
return;
}
renderer.dimensions = { columns: parseInt(columns, 10), rows: parseInt(rows, 10) };
});
});
})
);
});
}));
}
function colorText(text: string): string {
@ -250,7 +212,7 @@ function selectTerminal(): Thenable<vscode.Terminal> {
label: `name: ${t.name}`,
terminal: t
};
});
})
return vscode.window.showQuickPick(items).then(item => {
return item.terminal;
});
@ -262,4 +224,4 @@ function ensureTerminalExists(): boolean {
return false;
}
return true;
}
}

View File

@ -2,9 +2,9 @@
import * as vscode from 'vscode';
import { DepNodeProvider } from './nodeDependencies';
import { JsonOutlineProvider } from './jsonOutline';
import { FtpExplorer } from './ftpExplorer.textDocumentContentProvider';
import { DepNodeProvider } from './nodeDependencies'
import { JsonOutlineProvider } from './jsonOutline'
import { FtpExplorer } from './ftpExplorer.textDocumentContentProvider'
import { FileExplorer } from './fileExplorer';
export function activate(context: vscode.ExtensionContext) {
@ -19,19 +19,14 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider);
vscode.commands.registerCommand('nodeDependencies.refreshEntry', () => nodeDependenciesProvider.refresh());
vscode.commands.registerCommand('nodeDependencies.addEntry', node =>
vscode.window.showInformationMessage('Successfully called add entry')
);
vscode.commands.registerCommand('nodeDependencies.deleteEntry', node =>
vscode.window.showInformationMessage('Successfully called delete entry')
);
vscode.commands.registerCommand('extension.openPackageOnNpm', moduleName =>
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${moduleName}`))
);
vscode.commands.registerCommand('nodeDependencies.addEntry', node => vscode.window.showInformationMessage('Successfully called add entry'));
vscode.commands.registerCommand('nodeDependencies.deleteEntry', node => vscode.window.showInformationMessage('Successfully called delete entry'));
vscode.commands.registerCommand('extension.openPackageOnNpm', moduleName => vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${moduleName}`)));
vscode.window.registerTreeDataProvider('jsonOutline', jsonOutlineProvider);
vscode.commands.registerCommand('jsonOutline.refresh', () => jsonOutlineProvider.refresh());
vscode.commands.registerCommand('jsonOutline.refreshNode', offset => jsonOutlineProvider.refresh(offset));
vscode.commands.registerCommand('jsonOutline.renameNode', offset => jsonOutlineProvider.rename(offset));
vscode.commands.registerCommand('extension.openJsonSelection', range => jsonOutlineProvider.select(range));
}

View File

@ -7,12 +7,8 @@ import * as rimraf from 'rimraf';
//#region Utilities
namespace _ {
function handleResult<T>(
resolve: (result: T) => void,
reject: (error: Error) => void,
error: Error | null | undefined,
result: T
): void {
function handleResult<T>(resolve: (result: T) => void, reject: (error: Error) => void, error: Error | null | undefined, result: T): void {
if (error) {
reject(massageError(error));
} else {
@ -116,16 +112,11 @@ namespace _ {
}
export class FileStat implements vscode.FileStat {
constructor(private fsStat: fs.Stats) {}
constructor(private fsStat: fs.Stats) { }
get type(): vscode.FileType {
return this.fsStat.isFile()
? vscode.FileType.File
: this.fsStat.isDirectory()
? vscode.FileType.Directory
: this.fsStat.isSymbolicLink()
? vscode.FileType.SymbolicLink
: vscode.FileType.Unknown;
return this.fsStat.isFile() ? vscode.FileType.File : this.fsStat.isDirectory() ? vscode.FileType.Directory : this.fsStat.isSymbolicLink() ? vscode.FileType.SymbolicLink : vscode.FileType.Unknown;
}
get isFile(): boolean | undefined {
@ -154,13 +145,14 @@ export class FileStat implements vscode.FileStat {
}
interface Entry {
uri: vscode.Uri;
type: vscode.FileType;
uri: vscode.Uri,
type: vscode.FileType
}
//#endregion
export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscode.FileSystemProvider {
private _onDidChangeFile: vscode.EventEmitter<vscode.FileChangeEvent[]>;
constructor() {
@ -171,28 +163,17 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
return this._onDidChangeFile.event;
}
watch(uri: vscode.Uri, options: { recursive: boolean; excludes: string[] }): vscode.Disposable {
const watcher = fs.watch(
uri.fsPath,
{ recursive: options.recursive },
async (event: string, filename: string | Buffer) => {
const filepath = path.join(uri.fsPath, _.normalizeNFC(filename.toString()));
watch(uri: vscode.Uri, options: { recursive: boolean; excludes: string[]; }): vscode.Disposable {
const watcher = fs.watch(uri.fsPath, { recursive: options.recursive }, async (event: string, filename: string | Buffer) => {
const filepath = path.join(uri.fsPath, _.normalizeNFC(filename.toString()));
// TODO support excludes (using minimatch library?)
// TODO support excludes (using minimatch library?)
this._onDidChangeFile.fire([
{
type:
event === 'change'
? vscode.FileChangeType.Changed
: (await _.exists(filepath))
? vscode.FileChangeType.Created
: vscode.FileChangeType.Deleted,
uri: uri.with({ path: filepath })
} as vscode.FileChangeEvent
]);
}
);
this._onDidChangeFile.fire([{
type: event === 'change' ? vscode.FileChangeType.Changed : await _.exists(filepath) ? vscode.FileChangeType.Created : vscode.FileChangeType.Deleted,
uri: uri.with({ path: filepath })
} as vscode.FileChangeEvent]);
});
return { dispose: () => watcher.close() };
}
@ -230,19 +211,11 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
return _.readfile(uri.fsPath);
}
writeFile(
uri: vscode.Uri,
content: Uint8Array,
options: { create: boolean; overwrite: boolean }
): void | Thenable<void> {
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; }): void | Thenable<void> {
return this._writeFile(uri, content, options);
}
async _writeFile(
uri: vscode.Uri,
content: Uint8Array,
options: { create: boolean; overwrite: boolean }
): Promise<void> {
async _writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; }): Promise<void> {
const exists = await _.exists(uri.fsPath);
if (!exists) {
if (!options.create) {
@ -259,7 +232,7 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
return _.writefile(uri.fsPath, content as Buffer);
}
delete(uri: vscode.Uri, options: { recursive: boolean }): void | Thenable<void> {
delete(uri: vscode.Uri, options: { recursive: boolean; }): void | Thenable<void> {
if (options.recursive) {
return _.rmrf(uri.fsPath);
}
@ -267,11 +240,11 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
return _.unlink(uri.fsPath);
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void | Thenable<void> {
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): void | Thenable<void> {
return this._rename(oldUri, newUri, options);
}
async _rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): Promise<void> {
async _rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): Promise<void> {
const exists = await _.exists(newUri.fsPath);
if (exists) {
if (!options.overwrite) {
@ -305,25 +278,17 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
return a[0].localeCompare(b[0]);
}
return a[1] === vscode.FileType.Directory ? -1 : 1;
});
return children.map(([name, type]) => ({
uri: vscode.Uri.file(path.join(workspaceFolder.uri.fsPath, name)),
type
}));
})
return children.map(([name, type]) => ({ uri: vscode.Uri.file(path.join(workspaceFolder.uri.fsPath, name)), type }));
}
return [];
}
getTreeItem(element: Entry): vscode.TreeItem {
const treeItem = new vscode.TreeItem(
element.uri,
element.type === vscode.FileType.Directory
? vscode.TreeItemCollapsibleState.Collapsed
: vscode.TreeItemCollapsibleState.None
);
const treeItem = new vscode.TreeItem(element.uri, element.type === vscode.FileType.Directory ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
if (element.type === vscode.FileType.File) {
treeItem.command = { command: 'fileExplorer.openFile', title: 'Open File', arguments: [element.uri] };
treeItem.command = { command: 'fileExplorer.openFile', title: "Open File", arguments: [element.uri], };
treeItem.contextValue = 'file';
}
return treeItem;
@ -331,15 +296,16 @@ export class FileSystemProvider implements vscode.TreeDataProvider<Entry>, vscod
}
export class FileExplorer {
private fileExplorer: vscode.TreeView<Entry>;
constructor(context: vscode.ExtensionContext) {
const treeDataProvider = new FileSystemProvider();
this.fileExplorer = vscode.window.createTreeView('fileExplorer', { treeDataProvider });
vscode.commands.registerCommand('fileExplorer.openFile', resource => this.openResource(resource));
vscode.commands.registerCommand('fileExplorer.openFile', (resource) => this.openResource(resource));
}
private openResource(resource: vscode.Uri): void {
vscode.window.showTextDocument(resource);
}
}
}

View File

@ -8,14 +8,18 @@ interface IEntry {
}
export interface FtpNode {
resource: vscode.Uri;
isDirectory: boolean;
}
export class FtpModel {
private nodes: Map<string, FtpNode> = new Map<string, FtpNode>();
constructor(readonly host: string, private user: string, private password: string) {}
constructor(readonly host: string, private user: string, private password: string) {
}
public connect(): Thenable<Client> {
return new Promise((c, e) => {
@ -26,7 +30,7 @@ export class FtpModel {
client.on('error', error => {
e('Error while connecting: ' + error.message);
});
})
client.connect({
host: this.host,
@ -46,14 +50,7 @@ export class FtpModel {
client.end();
return c(
this.sort(
list.map(entry => ({
resource: vscode.Uri.parse(`ftp://${this.host}///${entry.name}`),
isDirectory: entry.type === 'd'
}))
)
);
return c(this.sort(list.map(entry => ({ resource: vscode.Uri.parse(`ftp://${this.host}///${entry.name}`), isDirectory: entry.type === 'd' }))));
});
});
});
@ -69,14 +66,7 @@ export class FtpModel {
client.end();
return c(
this.sort(
list.map(entry => ({
resource: vscode.Uri.parse(`${node.resource.fsPath}/${entry.name}`),
isDirectory: entry.type === 'd'
}))
)
);
return c(this.sort(list.map(entry => ({ resource: vscode.Uri.parse(`${node.resource.fsPath}/${entry.name}`), isDirectory: entry.type === 'd' }))));
});
});
});
@ -104,15 +94,15 @@ export class FtpModel {
return e(err);
}
let string = '';
stream.on('data', function(buffer) {
let string = ''
stream.on('data', function (buffer) {
if (buffer) {
var part = buffer.toString();
string += part;
}
});
stream.on('end', function() {
stream.on('end', function () {
client.end();
c(string);
});
@ -123,26 +113,26 @@ export class FtpModel {
}
export class FtpTreeDataProvider implements vscode.TreeDataProvider<FtpNode>, vscode.TextDocumentContentProvider {
private _onDidChangeTreeData: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
readonly onDidChangeTreeData: vscode.Event<any> = this._onDidChangeTreeData.event;
constructor(private readonly model: FtpModel) {}
constructor(private readonly model: FtpModel) { }
public refresh(): any {
this._onDidChangeTreeData.fire();
}
public getTreeItem(element: FtpNode): vscode.TreeItem {
return {
resourceUri: element.resource,
collapsibleState: element.isDirectory ? vscode.TreeItemCollapsibleState.Collapsed : void 0,
command: element.isDirectory
? void 0
: {
command: 'ftpExplorer.openFtpResource',
arguments: [element.resource],
title: 'Open FTP Resource'
}
command: element.isDirectory ? void 0 : {
command: 'ftpExplorer.openFtpResource',
arguments: [element.resource],
title: 'Open FTP Resource'
}
};
}
@ -161,6 +151,7 @@ export class FtpTreeDataProvider implements vscode.TreeDataProvider<FtpNode>, vs
}
export class FtpExplorer {
private ftpViewer: vscode.TreeView<FtpNode>;
constructor(context: vscode.ExtensionContext) {
@ -195,4 +186,4 @@ export class FtpExplorer {
}
return null;
}
}
}

View File

@ -1,41 +1,46 @@
import { Readable } from 'stream';
import { EventEmitter } from 'events';
declare namespace JSFtp {
interface JSFtpOptions {
host: string;
port?: number | 21;
user?: string | 'anonymous';
pass?: string | '@anonymous';
useList?: boolean;
}
interface Callback<T> {
(err: any, result: T): void;
}
interface Entry {
name: string;
size: number;
time: number;
type: 0 | 1;
}
interface JSFtpOptions {
host: string;
port?: number | 21;
user?: string | 'anonymous';
pass?: string | '@anonymous';
useList?: boolean
}
interface Callback<T> {
(err: any, result: T): void;
}
interface Entry {
name: string;
size: number;
time: number;
type: 0 | 1;
}
}
interface JSFtp extends EventEmitter {
auth(user: string, password: string, callback: JSFtp.Callback<void>): void;
keepAlive(wait?: number): void;
ls(path: string, callback: JSFtp.Callback<JSFtp.Entry[]>): void;
list(path: string, callback: JSFtp.Callback<any>): void;
put(buffer: Buffer, path: string, callback: JSFtp.Callback<void>): void;
get(path: string, callback: JSFtp.Callback<Readable>): void;
setType(type: 'A' | 'AN' | 'AT' | 'AC' | 'E' | 'I' | 'L', callback: JSFtp.Callback<any>): void;
raw(command: string, args: any[], callback: JSFtp.Callback<void>): void;
raw<T>(command: string, args: any[], callback: JSFtp.Callback<T>): void;
auth(user: string, password: string, callback: JSFtp.Callback<void>): void
keepAlive(wait?: number): void;
ls(path: string, callback: JSFtp.Callback<JSFtp.Entry[]>): void;
list(path: string, callback: JSFtp.Callback<any>): void;
put(buffer: Buffer, path: string, callback: JSFtp.Callback<void>): void;
get(path: string, callback: JSFtp.Callback<Readable>): void;
setType(type: 'A' | 'AN' | 'AT' | 'AC' | 'E' | 'I' | 'L', callback: JSFtp.Callback<any>): void;
raw(command: string, args: any[], callback: JSFtp.Callback<void>): void;
raw<T>(command: string, args: any[], callback: JSFtp.Callback<T>): void;
}
interface JSFtpConstructor {
new (options: JSFtp.JSFtpOptions): JSFtp;
new(options: JSFtp.JSFtpOptions): JSFtp;
}
declare const JSFtp: JSFtpConstructor;

View File

@ -4,6 +4,7 @@ import * as path from 'path';
import { isNumber } from 'util';
export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
private _onDidChangeTreeData: vscode.EventEmitter<number | null> = new vscode.EventEmitter<number | null>();
readonly onDidChangeTreeData: vscode.Event<number | null> = this._onDidChangeTreeData.event;
@ -33,34 +34,30 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
}
rename(offset: number): void {
vscode.window.showInputBox({ placeHolder: 'Enter the new label' }).then(value => {
if (value !== null && value !== undefined) {
this.editor.edit(editBuilder => {
const path = json.getLocation(this.text, offset).path;
let propertyNode = json.findNodeAtLocation(this.tree, path);
if (propertyNode.parent.type !== 'array') {
propertyNode = propertyNode.parent.children[0];
}
const range = new vscode.Range(
this.editor.document.positionAt(propertyNode.offset),
this.editor.document.positionAt(propertyNode.offset + propertyNode.length)
);
editBuilder.replace(range, `"${value}"`);
setTimeout(() => {
this.parseTree();
this.refresh(offset);
}, 100);
});
}
});
vscode.window.showInputBox({ placeHolder: 'Enter the new label' })
.then(value => {
if (value !== null && value !== undefined) {
this.editor.edit(editBuilder => {
const path = json.getLocation(this.text, offset).path
let propertyNode = json.findNodeAtLocation(this.tree, path);
if (propertyNode.parent.type !== 'array') {
propertyNode = propertyNode.parent.children[0];
}
const range = new vscode.Range(this.editor.document.positionAt(propertyNode.offset), this.editor.document.positionAt(propertyNode.offset + propertyNode.length));
editBuilder.replace(range, `"${value}"`);
setTimeout(() => {
this.parseTree();
this.refresh(offset);
}, 100)
});
}
});
}
private onActiveEditorChanged(): void {
if (vscode.window.activeTextEditor) {
if (vscode.window.activeTextEditor.document.uri.scheme === 'file') {
const enabled =
vscode.window.activeTextEditor.document.languageId === 'json' ||
vscode.window.activeTextEditor.document.languageId === 'jsonc';
const enabled = vscode.window.activeTextEditor.document.languageId === 'json' || vscode.window.activeTextEditor.document.languageId === 'jsonc';
vscode.commands.executeCommand('setContext', 'jsonOutlineEnabled', enabled);
if (enabled) {
this.refresh();
@ -95,7 +92,7 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
getChildren(offset?: number): Thenable<number[]> {
if (offset) {
const path = json.getLocation(this.text, offset).path;
const path = json.getLocation(this.text, offset).path
const node = json.findNodeAtLocation(this.tree, path);
return Promise.resolve(this.getChildrenOffsets(node));
} else {
@ -106,7 +103,7 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
private getChildrenOffsets(node: json.Node): number[] {
const offsets: number[] = [];
for (const child of node.children) {
const childPath = json.getLocation(this.text, child.offset).path;
const childPath = json.getLocation(this.text, child.offset).path
const childNode = json.findNodeAtLocation(this.tree, childPath);
if (childNode) {
offsets.push(childNode.offset);
@ -116,27 +113,15 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
}
getTreeItem(offset: number): vscode.TreeItem {
const path = json.getLocation(this.text, offset).path;
const path = json.getLocation(this.text, offset).path
const valueNode = json.findNodeAtLocation(this.tree, path);
if (valueNode) {
let hasChildren = valueNode.type === 'object' || valueNode.type === 'array';
let treeItem: vscode.TreeItem = new vscode.TreeItem(
this.getLabel(valueNode),
hasChildren
? valueNode.type === 'object'
? vscode.TreeItemCollapsibleState.Expanded
: vscode.TreeItemCollapsibleState.Collapsed
: vscode.TreeItemCollapsibleState.None
);
let treeItem: vscode.TreeItem = new vscode.TreeItem(this.getLabel(valueNode), hasChildren ? valueNode.type === 'object' ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
treeItem.command = {
command: 'extension.openJsonSelection',
title: '',
arguments: [
new vscode.Range(
this.editor.document.positionAt(valueNode.offset),
this.editor.document.positionAt(valueNode.offset + valueNode.length)
)
]
arguments: [new vscode.Range(this.editor.document.positionAt(valueNode.offset), this.editor.document.positionAt(valueNode.offset + valueNode.length))]
};
treeItem.iconPath = this.getIcon(valueNode);
treeItem.contextValue = valueNode.type;
@ -155,19 +140,19 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
return {
light: this.context.asAbsolutePath(path.join('resources', 'light', 'boolean.svg')),
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'boolean.svg'))
};
}
}
if (nodeType === 'string') {
return {
light: this.context.asAbsolutePath(path.join('resources', 'light', 'string.svg')),
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'string.svg'))
};
}
}
if (nodeType === 'number') {
return {
light: this.context.asAbsolutePath(path.join('resources', 'light', 'number.svg')),
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'number.svg'))
};
}
}
return null;
}
@ -182,7 +167,8 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
return prefix + ':[ ]';
}
return prefix + ':' + node.value.toString();
} else {
}
else {
const property = node.parent.children[0].value.toString();
if (node.type === 'array' || node.type === 'object') {
if (node.type === 'object') {
@ -192,13 +178,8 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<number> {
return '[ ] ' + property;
}
}
const value = this.editor.document.getText(
new vscode.Range(
this.editor.document.positionAt(node.offset),
this.editor.document.positionAt(node.offset + node.length)
)
);
const value = this.editor.document.getText(new vscode.Range(this.editor.document.positionAt(node.offset), this.editor.document.positionAt(node.offset + node.length)))
return `${property}: ${value}`;
}
}
}
}

View File

@ -3,12 +3,12 @@ import * as fs from 'fs';
import * as path from 'path';
export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
private _onDidChangeTreeData: vscode.EventEmitter<Dependency | undefined> = new vscode.EventEmitter<
Dependency | undefined
>();
private _onDidChangeTreeData: vscode.EventEmitter<Dependency | undefined> = new vscode.EventEmitter<Dependency | undefined>();
readonly onDidChangeTreeData: vscode.Event<Dependency | undefined> = this._onDidChangeTreeData.event;
constructor(private workspaceRoot: string) {}
constructor(private workspaceRoot: string) {
}
refresh(): void {
this._onDidChangeTreeData.fire();
@ -23,11 +23,9 @@ export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
vscode.window.showInformationMessage('No dependency in empty workspace');
return Promise.resolve([]);
}
if (element) {
return Promise.resolve(
this.getDepsInPackageJson(path.join(this.workspaceRoot, 'node_modules', element.label, 'package.json'))
);
return Promise.resolve(this.getDepsInPackageJson(path.join(this.workspaceRoot, 'node_modules', element.label, 'package.json')));
} else {
const packageJsonPath = path.join(this.workspaceRoot, 'package.json');
if (this.pathExists(packageJsonPath)) {
@ -37,6 +35,7 @@ export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
return Promise.resolve([]);
}
}
}
/**
@ -56,7 +55,7 @@ export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
arguments: [moduleName]
});
}
};
}
const deps = packageJson.dependencies
? Object.keys(packageJson.dependencies).map(dep => toDep(dep, packageJson.dependencies[dep]))
@ -82,6 +81,7 @@ export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
}
class Dependency extends vscode.TreeItem {
constructor(
public readonly label: string,
private version: string,
@ -92,7 +92,7 @@ class Dependency extends vscode.TreeItem {
}
get tooltip(): string {
return `${this.label}-${this.version}`;
return `${this.label}-${this.version}`
}
iconPath = {
@ -101,4 +101,5 @@ class Dependency extends vscode.TreeItem {
};
contextValue = 'dependency';
}

View File

@ -14,9 +14,9 @@ export enum Mode {
}
export interface ModifierKeys {
ctrl?: boolean;
alt?: boolean;
shifit?: boolean;
ctrl?: boolean,
alt?: boolean,
shifit?: boolean
}
export class DeleteRegister {
@ -42,10 +42,12 @@ export interface IController {
}
export abstract class AbstractCommandDescriptor {
public abstract createCommand(args?: any): Command;
}
export interface Command {
commandId: string;
args?: any[];
commandId: string,
args?: any[]
}

View File

@ -4,7 +4,15 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextEditorCursorStyle, Position, Range, Selection, TextEditor, TextEditorRevealType, window } from 'vscode';
import {
TextEditorCursorStyle,
Position,
Range,
Selection,
TextEditor,
TextEditorRevealType,
window
} from 'vscode';
import { Words } from './words';
import { MotionState, Motion } from './motions';
@ -17,28 +25,19 @@ export interface ITypeResult {
}
export class Controller implements IController {
private _currentMode: Mode;
private _currentInput: string;
private _motionState: MotionState;
private _isVisual: boolean;
public get motionState(): MotionState {
return this._motionState;
}
public findMotion(input: string): Motion {
return Mappings.findMotion(input);
}
public isMotionPrefix(input: string): boolean {
return Mappings.isMotionPrefix(input);
}
public get motionState(): MotionState { return this._motionState; }
public findMotion(input: string): Motion { return Mappings.findMotion(input); }
public isMotionPrefix(input: string): boolean { return Mappings.isMotionPrefix(input); }
private _deleteRegister: DeleteRegister;
public setDeleteRegister(register: DeleteRegister): void {
this._deleteRegister = register;
}
public getDeleteRegister(): DeleteRegister {
return this._deleteRegister;
}
public setDeleteRegister(register: DeleteRegister): void { this._deleteRegister = register; }
public getDeleteRegister(): DeleteRegister { return this._deleteRegister; }
constructor() {
this._motionState = new MotionState();
@ -181,13 +180,11 @@ export class Controller implements IController {
if (this._currentMode === Mode.REPLACE) {
let pos = editor.selection.active;
editor
.edit(builder => {
builder.replace(new Range(pos.line, pos.character, pos.line, pos.character + 1), text);
})
.then(() => {
setPositionAndReveal(editor, pos.line, pos.character + 1);
});
editor.edit((builder) => {
builder.replace(new Range(pos.line, pos.character, pos.line, pos.character + 1), text);
}).then(() => {
setPositionAndReveal(editor, pos.line, pos.character + 1);
});
return Promise.resolve({
hasConsumedInput: true,
@ -210,7 +207,7 @@ export class Controller implements IController {
if (this._currentMode === Mode.REPLACE) {
let pos = editor.selection.active;
editor.edit(builder => {
editor.edit((builder) => {
builder.replace(new Range(pos.line, pos.character - replaceCharCnt, pos.line, pos.character), text);
});
@ -222,7 +219,7 @@ export class Controller implements IController {
private _interpretNormalModeInput(editor: TextEditor, modifierKeys: ModifierKeys): Thenable<ITypeResult> {
if (this._currentInput.startsWith(':')) {
return window.showInputBox({ value: 'tabm' }).then(value => {
return window.showInputBox({ value: 'tabm' }).then((value) => {
return this._findMapping(value || '', editor, modifierKeys);
});
}

View File

@ -18,7 +18,7 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand(commandId, run));
}
function registerCtrlKeyBinding(key: string): void {
registerCommandNice(key, function(args) {
registerCommandNice(key, function (args) {
if (!vscode.window.activeTextEditor) {
return;
}
@ -28,34 +28,34 @@ export function activate(context: vscode.ExtensionContext) {
let vimExt = new VimExt();
registerCommandNice('type', function(args) {
registerCommandNice('type', function (args) {
if (!vscode.window.activeTextEditor) {
return;
}
vimExt.type(args.text);
});
registerCommandNice('replacePreviousChar', function(args) {
registerCommandNice('replacePreviousChar', function (args) {
if (!vscode.window.activeTextEditor) {
return;
}
vimExt.replacePrevChar(args.text, args.replaceCharCnt);
});
registerCommandNice('compositionStart', function(args) {
registerCommandNice('compositionStart', function (args) {
if (!vscode.window.activeTextEditor) {
return;
}
vimExt.compositionStart();
});
registerCommandNice('compositionEnd', function(args) {
registerCommandNice('compositionEnd', function (args) {
if (!vscode.window.activeTextEditor) {
return;
}
vimExt.compositionEnd();
});
registerCommandNice('vim.goToNormalMode', function(args) {
registerCommandNice('vim.goToNormalMode', function (args) {
vimExt.goToNormalMode();
});
registerCommandNice('vim.clearInput', function(args) {
registerCommandNice('vim.clearInput', function (args) {
vimExt.clearInput();
});
// registerCommandNice('paste', function(args) {
@ -84,6 +84,7 @@ function getConfiguredWordSeparators(): string {
}
class VimExt {
private _inNormalMode: ContextKey;
private _hasInput: ContextKey;
private _statusBar: StatusBar;
@ -94,16 +95,16 @@ class VimExt {
this._hasInput = new ContextKey('vim.hasInput');
this._statusBar = new StatusBar();
this._controller = new Controller();
this._controller = new Controller()
vscode.window.onDidChangeActiveTextEditor(textEditor => {
vscode.window.onDidChangeActiveTextEditor((textEditor) => {
if (!textEditor) {
return;
}
this._ensureState();
});
vscode.window.onDidChangeTextEditorSelection(e => {
vscode.window.onDidChangeTextEditorSelection((e) => {
let isVisual = this._controller.getVisual();
if (!isVisual) {
@ -153,7 +154,7 @@ class VimExt {
}
public type(text: string, modifierKeys: ModifierKeys = { ctrl: false, shifit: false, alt: false }): void {
this._controller.type(vscode.window.activeTextEditor, text, modifierKeys).then(r => {
this._controller.type(vscode.window.activeTextEditor, text, modifierKeys).then((r) => {
if (r.hasConsumedInput) {
this._ensureState();
if (r.executeEditorCommand) {
@ -185,7 +186,7 @@ class VimExt {
}
public compositionEnd(): void {
this._controller.compositionEnd(vscode.window.activeTextEditor).then(r => {
this._controller.compositionEnd(vscode.window.activeTextEditor).then((r) => {
if (r.hasConsumedInput) {
this._ensureState();
if (r.executeEditorCommand) {

View File

@ -9,47 +9,43 @@ import { Motion, Motions } from './motions';
import { Operator, Operators } from './operators';
import { IController, Command, AbstractCommandDescriptor, ModifierKeys } from './common';
const CHAR_TO_BINDING: { [char: string]: any } = {};
const CHAR_TO_BINDING: { [char: string]: any; } = {};
function defineBinding(char: string, value: any, modifierKeys: ModifierKeys): void {
let key = modifierKeys.ctrl ? 'CTRL + ' + char : char;
CHAR_TO_BINDING[key] = value;
}
};
function getBinding(char: string, modifierKeys: ModifierKeys): any {
let key = modifierKeys.ctrl ? 'CTRL + ' + char : char;
return CHAR_TO_BINDING[key];
}
};
function defineOperator(char: string, operator: Operator, modifierKeys: ModifierKeys = {}): void {
defineBinding(char + '__operator__', operator, modifierKeys);
}
};
function getOperator(char: string, modifierKeys: ModifierKeys = {}): Operator {
return getBinding(char + '__operator__', modifierKeys);
}
};
function defineCommand(char: string, commandId: string, modifierKeys: ModifierKeys = {}): void {
defineBinding(char + '__command__', { commandId: commandId }, modifierKeys);
}
};
function getCommand(char: string, modifierKeys: ModifierKeys = {}): Command {
return getBinding(char + '__command__', modifierKeys);
}
};
function defineMotion(char: string, motion: Motion, modifierKeys: ModifierKeys = {}): void {
defineBinding(char + '__motion__', motion, modifierKeys);
}
};
function getMotion(char: string, modifierKeys: ModifierKeys = {}): Motion {
return getBinding(char + '__motion__', modifierKeys);
}
};
function defineMotionCommand(
char: string,
motionCommand: AbstractCommandDescriptor,
modifierKeys: ModifierKeys = {}
): void {
function defineMotionCommand(char: string, motionCommand: AbstractCommandDescriptor, modifierKeys: ModifierKeys = {}): void {
defineBinding(char + '__motioncommand__', motionCommand, modifierKeys);
}
};
function getMotionCommand(char: string, modifierKeys: ModifierKeys = {}): AbstractCommandDescriptor {
return getBinding(char + '__motioncommand__', modifierKeys);
}
};
// Operators
defineOperator('x', Operators.DeleteCharUnderCursor);
@ -124,12 +120,14 @@ defineMotionCommand('zb', Motions.RevealCurrentLineAtBottom);
defineMotionCommand('zc', Motions.FoldUnder);
defineMotionCommand('zo', Motions.UnfoldUnder);
export interface IFoundOperator {
runNormal(controller: IController, editor: TextEditor): boolean;
runVisual(controller: IController, editor: TextEditor): boolean;
}
export class Mappings {
public static findMotion(input: string): Motion {
let parsed = _parseNumberAndString(input);
let motion = getMotion(parsed.input.substr(0, 1));
@ -152,11 +150,7 @@ export class Mappings {
return command;
}
private static findMotionCommandFromNumberAndString(
numberAndString: INumberAndString,
isVisual: boolean,
modifierKeys: ModifierKeys
): Command {
private static findMotionCommandFromNumberAndString(numberAndString: INumberAndString, isVisual: boolean, modifierKeys: ModifierKeys): Command {
let motionCommand = getMotionCommand(numberAndString.input.substr(0, 1), modifierKeys);
if (!motionCommand) {
motionCommand = getMotionCommand(numberAndString.input.substr(0, 2), modifierKeys);
@ -170,12 +164,7 @@ export class Mappings {
if (!motionCommand) {
motionCommand = getMotionCommand(numberAndString.input, modifierKeys);
}
return motionCommand
? motionCommand.createCommand({
isVisual: isVisual,
repeat: numberAndString.hasRepeatCount ? numberAndString.repeatCount : undefined
})
: null;
return motionCommand ? motionCommand.createCommand({ isVisual: isVisual, repeat: numberAndString.hasRepeatCount ? numberAndString.repeatCount : undefined }) : null;
}
public static findOperator(input: string, modifierKeys: ModifierKeys): IFoundOperator {
@ -234,7 +223,7 @@ function _parseNumberAndString(input: string, numberAtBeginning: boolean = true)
hasRepeatCount: false,
repeatCount: 1,
input: input
};
}
}
interface INumberAndString {

View File

@ -9,6 +9,7 @@ import { Words, WordCharacters } from './words';
import { Command, AbstractCommandDescriptor } from './common';
export class MotionState {
public anchor: Position;
public cursorDesiredCharacter: number;
public wordCharacterClass: WordCharacters;
@ -18,6 +19,7 @@ export class MotionState {
this.wordCharacterClass = null;
this.anchor = null;
}
}
export abstract class Motion {
@ -32,6 +34,7 @@ export abstract class Motion {
}
class RepeatingMotion extends Motion {
private _actual: Motion;
private _repeatCount: number;
@ -53,7 +56,7 @@ class NextCharacterMotion extends Motion {
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
if (pos.character === doc.lineAt(pos.line).text.length) {
// on last character
return pos.line + 1 < doc.lineCount ? new Position(pos.line + 1, 0) : pos;
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
}
return new Position(pos.line, pos.character + 1);
@ -77,7 +80,7 @@ class DownMotion extends Motion {
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
let line = pos.line;
state.cursorDesiredCharacter = state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter;
state.cursorDesiredCharacter = (state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter);
if (line < doc.lineCount - 1) {
line++;
@ -92,7 +95,7 @@ class UpMotion extends Motion {
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
let line = pos.line;
state.cursorDesiredCharacter = state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter;
state.cursorDesiredCharacter = (state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter);
if (line > 0) {
line--;
@ -135,7 +138,7 @@ class NextWordStartMotion extends Motion {
if (pos.character >= lineContent.length - 1) {
// cursor at end of line
return pos.line + 1 < doc.lineCount ? new Position(pos.line + 1, 0) : pos;
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
}
let nextWord = Words.findNextWord(doc, pos, state.wordCharacterClass);
@ -168,7 +171,7 @@ class NextWordEndMotion extends Motion {
if (pos.character >= lineContent.length - 1) {
// no content on this line or cursor at end of line
return pos.line + 1 < doc.lineCount ? new Position(pos.line + 1, 0) : pos;
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
}
let nextWord = Words.findNextWord(doc, pos, state.wordCharacterClass);
@ -198,6 +201,7 @@ class GoToLineUndefinedMotion extends Motion {
}
abstract class GoToLineMotion extends Motion {
protected firstNonWhitespaceChar(doc: TextDocument, line: number): number {
let lineContent = doc.lineAt(line).text;
let character = 0;
@ -210,6 +214,7 @@ abstract class GoToLineMotion extends Motion {
}
return character;
}
}
class GoToFirstLineMotion extends GoToLineMotion {
@ -240,6 +245,7 @@ class GoToLineDefinedMotion extends GoToLineMotion {
}
class CursorMoveCommand extends AbstractCommandDescriptor {
constructor(private to: string, private by?: string) {
super();
}
@ -250,7 +256,7 @@ class CursorMoveCommand extends AbstractCommandDescriptor {
by: this.by,
value: args.repeat || 1,
select: !!args.isVisual
};
}
return {
commandId: 'cursorMove',
args: cursorMoveArgs
@ -259,6 +265,7 @@ class CursorMoveCommand extends AbstractCommandDescriptor {
}
class EditorScrollCommand extends AbstractCommandDescriptor {
constructor(private to: string, private by?: string) {
super();
}
@ -269,7 +276,7 @@ class EditorScrollCommand extends AbstractCommandDescriptor {
by: this.by,
value: args.repeat || 1,
revealCursor: true
};
}
return {
commandId: 'editorScroll',
args: editorScrollArgs
@ -278,6 +285,7 @@ class EditorScrollCommand extends AbstractCommandDescriptor {
}
class RevealCurrentLineCommand extends AbstractCommandDescriptor {
constructor(private at: string) {
super();
}
@ -296,6 +304,7 @@ class RevealCurrentLineCommand extends AbstractCommandDescriptor {
}
class MoveActiveEditorCommandByPosition extends AbstractCommandDescriptor {
constructor() {
super();
}
@ -304,7 +313,7 @@ class MoveActiveEditorCommandByPosition extends AbstractCommandDescriptor {
let moveActiveEditorArgs: any = {
to: args.repeat === void 0 ? 'last' : 'position',
value: args.repeat !== void 0 ? args.repeat + 1 : undefined
};
}
return {
commandId: 'moveActiveEditor',
args: moveActiveEditorArgs
@ -313,6 +322,7 @@ class MoveActiveEditorCommandByPosition extends AbstractCommandDescriptor {
}
class MoveActiveEditorCommand extends AbstractCommandDescriptor {
constructor(private to: string) {
super();
}
@ -321,7 +331,7 @@ class MoveActiveEditorCommand extends AbstractCommandDescriptor {
let moveActiveEditorArgs: any = {
to: this.to,
value: args.repeat ? args.repeat : 1
};
}
return {
commandId: 'moveActiveEditor',
args: moveActiveEditorArgs
@ -329,6 +339,7 @@ class MoveActiveEditorCommand extends AbstractCommandDescriptor {
}
}
class FoldCommand extends AbstractCommandDescriptor {
constructor() {
super();
}
@ -337,7 +348,7 @@ class FoldCommand extends AbstractCommandDescriptor {
let foldEditorArgs: any = {
levels: args.repeat ? args.repeat : 1,
direction: 'up'
};
}
return {
commandId: 'editor.fold',
args: foldEditorArgs
@ -346,6 +357,7 @@ class FoldCommand extends AbstractCommandDescriptor {
}
class UnfoldCommand extends AbstractCommandDescriptor {
constructor() {
super();
}
@ -354,7 +366,7 @@ class UnfoldCommand extends AbstractCommandDescriptor {
let foldEditorArgs: any = {
levels: args.repeat ? args.repeat : 1,
direction: 'up'
};
}
return {
commandId: 'editor.unfold',
args: foldEditorArgs

View File

@ -9,6 +9,7 @@ import { MotionState, Motion, Motions } from './motions';
import { Mode, IController, DeleteRegister } from './common';
export abstract class Operator {
public abstract runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean;
public abstract runVisualMode(ctrl: IController, ed: TextEditor, args: string): boolean;
@ -31,7 +32,7 @@ export abstract class Operator {
protected delete(ctrl: IController, ed: TextEditor, isWholeLine: boolean, range: Range): void {
ctrl.setDeleteRegister(new DeleteRegister(isWholeLine, ed.document.getText(range)));
ed.edit(builder => {
ed.edit((builder) => {
builder.delete(range);
});
}
@ -80,11 +81,7 @@ class VisualOperator extends OperatorWithNoArgs {
class DeleteCharUnderCursorOperator extends Operator {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
let to = Motions.NextCharacter.repeat(repeatCount > 1, repeatCount).run(
this.doc(ed),
this.pos(ed),
ctrl.motionState
);
let to = Motions.NextCharacter.repeat(repeatCount > 1, repeatCount).run(this.doc(ed), this.pos(ed), ctrl.motionState);
let from = this.pos(ed);
this.delete(ctrl, ed, false, new Range(from.line, from.character, to.line, to.character));
@ -137,6 +134,7 @@ abstract class OperatorWithMotion extends Operator {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
let motion = ctrl.findMotion(args);
if (!motion) {
// is it motion building
if (ctrl.isMotionPrefix(args)) {
return false;
@ -153,6 +151,7 @@ abstract class OperatorWithMotion extends Operator {
}
class DeleteToOperator extends OperatorWithMotion {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
if (args === 'd') {
// dd
@ -178,6 +177,7 @@ class DeleteToOperator extends OperatorWithMotion {
}
class PutOperator extends Operator {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
let register = ctrl.getDeleteRegister();
if (!register) {
@ -189,7 +189,7 @@ class PutOperator extends Operator {
let pos = this.pos(ed);
if (!register.isWholeLine) {
ed.edit(builder => {
ed.edit((builder) => {
builder.insert(new Position(pos.line, pos.character + 1), str);
});
return true;
@ -206,7 +206,7 @@ class PutOperator extends Operator {
str = '\n' + str;
}
ed.edit(builder => {
ed.edit((builder) => {
builder.insert(new Position(insertLine, insertCharacter), str);
});
@ -223,7 +223,7 @@ class PutOperator extends Operator {
let str = register.content;
let sel = this.sel(ed);
ed.edit(builder => {
ed.edit((builder) => {
builder.replace(sel, str);
});
@ -232,6 +232,7 @@ class PutOperator extends Operator {
}
class ReplaceOperator extends Operator {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
if (args.length === 0) {
// input not ready
@ -246,7 +247,7 @@ class ReplaceOperator extends Operator {
return true;
}
ed.edit(builder => {
ed.edit((builder) => {
builder.replace(new Range(pos.line, pos.character, pos.line, toCharacter), repeatString(args, repeatCount));
});
@ -273,7 +274,7 @@ class ReplaceOperator extends Operator {
}
}
ed.edit(builder => {
ed.edit((builder) => {
builder.replace(sel, dstString);
});
@ -282,6 +283,7 @@ class ReplaceOperator extends Operator {
}
class ReplaceModeOperator extends Operator {
public runNormalMode(ctrl: IController, ed: TextEditor, repeatCount: number, args: string): boolean {
ctrl.setMode(Mode.REPLACE);
return true;
@ -292,9 +294,11 @@ class ReplaceModeOperator extends Operator {
ctrl.setMode(Mode.INSERT);
return true;
}
}
class ChangeOperator extends OperatorWithMotion {
protected _runNormalMode(ctrl: IController, ed: TextEditor, motion: Motion): boolean {
let to = motion.run(this.doc(ed), this.pos(ed), ctrl.motionState);
let from = this.pos(ed);
@ -336,5 +340,5 @@ export const Operators = {
Put: new PutOperator(),
Replace: new ReplaceOperator(),
Change: new ChangeOperator(),
ReplaceMode: new ReplaceModeOperator()
ReplaceMode: new ReplaceModeOperator(),
};

View File

@ -27,6 +27,7 @@ export interface IWord {
}
export class Words {
public static createWordCharacters(wordSeparators: string): WordCharacters {
let result: CharacterClass[] = [];
@ -46,67 +47,43 @@ export class Words {
}
public static findNextWord(doc: TextDocument, pos: Position, wordCharacterClass: WordCharacters): IWord {
let lineContent = doc.lineAt(pos.line).text;
let wordType = WordType.NONE;
let len = lineContent.length;
for (let chIndex = pos.character; chIndex < len; chIndex++) {
let chCode = lineContent.charCodeAt(chIndex);
let chClass = wordCharacterClass[chCode] || CharacterClass.REGULAR;
let chClass = (wordCharacterClass[chCode] || CharacterClass.REGULAR);
if (chClass === CharacterClass.REGULAR) {
if (wordType === WordType.SEPARATOR) {
return this._createWord(
lineContent,
wordType,
this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1),
chIndex
);
return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1), chIndex);
}
wordType = WordType.REGULAR;
} else if (chClass === CharacterClass.WORD_SEPARATOR) {
if (wordType === WordType.REGULAR) {
return this._createWord(
lineContent,
wordType,
this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1),
chIndex
);
return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1), chIndex);
}
wordType = WordType.SEPARATOR;
} else if (chClass === CharacterClass.WHITESPACE) {
if (wordType !== WordType.NONE) {
return this._createWord(
lineContent,
wordType,
this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1),
chIndex
);
return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordCharacterClass, wordType, chIndex - 1), chIndex);
}
}
}
if (wordType !== WordType.NONE) {
return this._createWord(
lineContent,
wordType,
this._findStartOfWord(lineContent, wordCharacterClass, wordType, len - 1),
len
);
return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordCharacterClass, wordType, len - 1), len);
}
return null;
}
private static _findStartOfWord(
lineContent: string,
wordCharacterClass: WordCharacters,
wordType: WordType,
startIndex: number
): number {
private static _findStartOfWord(lineContent: string, wordCharacterClass: WordCharacters, wordType: WordType, startIndex: number): number {
for (let chIndex = startIndex; chIndex >= 0; chIndex--) {
let chCode = lineContent.charCodeAt(chIndex);
let chClass = wordCharacterClass[chCode] || CharacterClass.REGULAR;
let chClass = (wordCharacterClass[chCode] || CharacterClass.REGULAR);
if (chClass === CharacterClass.WHITESPACE) {
return chIndex + 1;

View File

@ -8,9 +8,10 @@ import * as vscode from 'vscode';
import { add } from './math';
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('extension.helloWebpack', () => {
vscode.window.showInformationMessage(`41 + 1 = ${add(41, 1)}`);
});
context.subscriptions.push(disposable);
let disposable = vscode.commands.registerCommand('extension.helloWebpack', () => {
vscode.window.showInformationMessage(`41 + 1 = ${add(41, 1)}`);
});
context.subscriptions.push(disposable);
}

View File

@ -5,9 +5,9 @@
'use strict';
export function add(a: number, b: number): number {
return a + b;
return a + b;
}
export function sub(a: number, b: number): number {
return a - b;
return a - b;
}

View File

@ -2,173 +2,164 @@ import * as path from 'path';
import * as vscode from 'vscode';
const cats = {
'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif',
'Testing Cat': 'https://media.giphy.com/media/3oriO0OEd9QIDdllqo/giphy.gif'
'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif',
'Testing Cat': 'https://media.giphy.com/media/3oriO0OEd9QIDdllqo/giphy.gif'
};
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand('catCoding.start', () => {
CatCodingPanel.createOrShow(context.extensionPath);
})
);
context.subscriptions.push(
vscode.commands.registerCommand('catCoding.doRefactor', () => {
if (CatCodingPanel.currentPanel) {
CatCodingPanel.currentPanel.doRefactor();
}
})
);
context.subscriptions.push(vscode.commands.registerCommand('catCoding.start', () => {
CatCodingPanel.createOrShow(context.extensionPath);
}));
if (vscode.window.registerWebviewPanelSerializer) {
// Make sure we register a serilizer in activation event
vscode.window.registerWebviewPanelSerializer(CatCodingPanel.viewType, {
async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
console.log(`Got state: ${state}`);
CatCodingPanel.revive(webviewPanel, context.extensionPath);
}
});
}
context.subscriptions.push(vscode.commands.registerCommand('catCoding.doRefactor', () => {
if (CatCodingPanel.currentPanel) {
CatCodingPanel.currentPanel.doRefactor();
}
}));
if (vscode.window.registerWebviewPanelSerializer) {
// Make sure we register a serilizer in activation event
vscode.window.registerWebviewPanelSerializer(CatCodingPanel.viewType, {
async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
console.log(`Got state: ${state}`);
CatCodingPanel.revive(webviewPanel, context.extensionPath);
}
});
}
}
/**
* Manages cat coding webview panels
*/
class CatCodingPanel {
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
public static currentPanel: CatCodingPanel | undefined;
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
public static currentPanel: CatCodingPanel | undefined;
public static readonly viewType = 'catCoding';
public static readonly viewType = 'catCoding';
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionPath: string;
private _disposables: vscode.Disposable[] = [];
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionPath: string;
private _disposables: vscode.Disposable[] = [];
public static createOrShow(extensionPath: string) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
public static createOrShow(extensionPath: string) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
// If we already have a panel, show it.
if (CatCodingPanel.currentPanel) {
CatCodingPanel.currentPanel._panel.reveal(column);
return;
}
// If we already have a panel, show it.
if (CatCodingPanel.currentPanel) {
CatCodingPanel.currentPanel._panel.reveal(column);
return;
}
// Otherwise, create a new panel.
const panel = vscode.window.createWebviewPanel(
CatCodingPanel.viewType,
'Cat Coding',
column || vscode.ViewColumn.One,
{
// Enable javascript in the webview
enableScripts: true,
// Otherwise, create a new panel.
const panel = vscode.window.createWebviewPanel(CatCodingPanel.viewType, "Cat Coding", column || vscode.ViewColumn.One, {
// 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(extensionPath, 'media'))]
}
);
// And restric the webview to only loading content from our extension's `media` directory.
localResourceRoots: [
vscode.Uri.file(path.join(extensionPath, 'media'))
]
});
CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionPath);
}
CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionPath);
}
public static revive(panel: vscode.WebviewPanel, extensionPath: string) {
CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionPath);
}
public static revive(panel: vscode.WebviewPanel, extensionPath: string) {
CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionPath);
}
private constructor(panel: vscode.WebviewPanel, extensionPath: string) {
this._panel = panel;
this._extensionPath = extensionPath;
private constructor(
panel: vscode.WebviewPanel,
extensionPath: string
) {
this._panel = panel;
this._extensionPath = extensionPath;
// Set the webview's initial html content
this._update();
// Set the webview's initial html content
this._update();
// 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);
// 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);
// Update the content based on view changes
this._panel.onDidChangeViewState(
e => {
if (this._panel.visible) {
this._update();
}
},
null,
this._disposables
);
// Update the content based on view changes
this._panel.onDidChangeViewState(e => {
if (this._panel.visible) {
this._update()
}
}, null, this._disposables);
// Handle messages from the webview
this._panel.webview.onDidReceiveMessage(
message => {
switch (message.command) {
case 'alert':
vscode.window.showErrorMessage(message.text);
return;
}
},
null,
this._disposables
);
}
// Handle messages from the webview
this._panel.webview.onDidReceiveMessage(message => {
switch (message.command) {
case 'alert':
vscode.window.showErrorMessage(message.text);
return;
}
}, null, this._disposables);
}
public doRefactor() {
// Send a message to the webview webview.
// You can send any JSON serializable data.
this._panel.webview.postMessage({ command: 'refactor' });
}
public doRefactor() {
// Send a message to the webview webview.
// You can send any JSON serializable data.
this._panel.webview.postMessage({ command: 'refactor' });
}
public dispose() {
CatCodingPanel.currentPanel = undefined;
public dispose() {
CatCodingPanel.currentPanel = undefined;
// Clean up our resources
this._panel.dispose();
// Clean up our resources
this._panel.dispose();
while (this._disposables.length) {
const x = this._disposables.pop();
if (x) {
x.dispose();
}
}
}
while (this._disposables.length) {
const x = this._disposables.pop();
if (x) {
x.dispose();
}
}
}
private _update() {
const z = 1 + 2;
// Vary the webview's content based on where it is located in the editor.
switch (this._panel.viewColumn) {
case vscode.ViewColumn.Two:
this._updateForCat('Compiling Cat');
return;
private _update() {
case vscode.ViewColumn.Three:
this._updateForCat('Testing Cat');
return;
const z = 1 + 2;
// Vary the webview's content based on where it is located in the editor.
switch (this._panel.viewColumn) {
case vscode.ViewColumn.Two:
this._updateForCat('Compiling Cat');
return;
case vscode.ViewColumn.One:
default:
this._updateForCat('Coding Cat');
return;
}
}
case vscode.ViewColumn.Three:
this._updateForCat('Testing Cat');
return;
private _updateForCat(catName: keyof typeof cats) {
this._panel.title = catName;
this._panel.webview.html = this._getHtmlForWebview(cats[catName]);
}
case vscode.ViewColumn.One:
default:
this._updateForCat('Coding Cat');
return;
}
}
private _getHtmlForWebview(catGif: string) {
// Local path to main script run in the webview
const scriptPathOnDisk = vscode.Uri.file(path.join(this._extensionPath, 'media', 'main.js'));
private _updateForCat(catName: keyof typeof cats) {
this._panel.title = catName;
this._panel.webview.html = this._getHtmlForWebview(cats[catName]);
}
// And the uri we use to load this script in the webview
const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' });
private _getHtmlForWebview(catGif: string) {
// Use a nonce to whitelist which scripts can be run
const nonce = getNonce();
// Local path to main script run in the webview
const scriptPathOnDisk = vscode.Uri.file(path.join(this._extensionPath, 'media', 'main.js'));
return `<!DOCTYPE html>
// And the uri we use to load this script in the webview
const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' });
// Use a nonce to whitelist which scripts can be run
const nonce = getNonce();
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
@ -189,14 +180,14 @@ class CatCodingPanel {
<script nonce="${nonce}" src="${scriptUri}"></script>
</body>
</html>`;
}
}
}
function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
let text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}