- Show mongo as an explorer view
- Implement connect to database feature - Implement new scrapbook feature - Remove the linking between scrapbook and explorer - Create an untitled file for result
This commit is contained in:
Родитель
4696ee6826
Коммит
6058bf0705
78
package.json
78
package.json
|
@ -25,13 +25,6 @@
|
||||||
],
|
],
|
||||||
"main": "./out/src/extension",
|
"main": "./out/src/extension",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"views": [
|
|
||||||
{
|
|
||||||
"id": "mongoExplorer",
|
|
||||||
"label": "Mongo",
|
|
||||||
"icon": "resources/icons/database.png"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"languages": [
|
"languages": [
|
||||||
{
|
{
|
||||||
"id": "mongo",
|
"id": "mongo",
|
||||||
|
@ -54,20 +47,11 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
|
||||||
"command": "mongo.resource.onClick",
|
|
||||||
"title": "Open Mongo Shell Editor"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"category": "Mongo",
|
"category": "Mongo",
|
||||||
"command": "mongo.execute",
|
"command": "mongo.execute",
|
||||||
"title": "Execute Script"
|
"title": "Execute Script"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"category": "Mongo",
|
|
||||||
"command": "mongo.executeLine",
|
|
||||||
"title": "Execute Script at cursor"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"category": "Mongo",
|
"category": "Mongo",
|
||||||
"command": "mongo.addServer",
|
"command": "mongo.addServer",
|
||||||
|
@ -81,6 +65,34 @@
|
||||||
"category": "Mongo",
|
"category": "Mongo",
|
||||||
"command": "mongo.removeServer",
|
"command": "mongo.removeServer",
|
||||||
"title": "Remove Server"
|
"title": "Remove Server"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "Mongo",
|
||||||
|
"command": "mongo.connect",
|
||||||
|
"title": "Connect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "Mongo",
|
||||||
|
"command": "mongo.connectDb",
|
||||||
|
"title": "Connect Database"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "Mongo",
|
||||||
|
"command": "mongo.newScrapbook",
|
||||||
|
"title": "New Scrapbook",
|
||||||
|
"icon": {
|
||||||
|
"light": "resources/icons/light/addFile.svg",
|
||||||
|
"dark": "resources/icons/dark/addFile.svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "Mongo",
|
||||||
|
"command": "mongo.refreshExplorer",
|
||||||
|
"title": "Refresh",
|
||||||
|
"icon": {
|
||||||
|
"light": "resources/icons/light/refresh.svg",
|
||||||
|
"dark": "resources/icons/dark/refresh.svg"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
|
@ -88,35 +100,49 @@
|
||||||
{
|
{
|
||||||
"command": "mongo.execute",
|
"command": "mongo.execute",
|
||||||
"when": "resourceLangId==mongo"
|
"when": "resourceLangId==mongo"
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mongo.executeLine",
|
|
||||||
"when": "resourceLangId==mongo"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/title": [
|
"view/title": [
|
||||||
|
{
|
||||||
|
"command": "mongo.refreshExplorer",
|
||||||
|
"when": "view == mongoExplorer",
|
||||||
|
"group": "navigation"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "mongo.addServer",
|
"command": "mongo.addServer",
|
||||||
"when": "view == mongoExplorer",
|
"when": "view == mongoExplorer",
|
||||||
"group": "navigation"
|
"group": "navigation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mongo.newScrapbook",
|
||||||
|
"when": "view == mongoExplorer",
|
||||||
|
"group": "navigation"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"view/resource": [
|
"view/resource": [
|
||||||
{
|
{
|
||||||
"command": "mongo.removeServer",
|
"command": "mongo.removeServer",
|
||||||
"when": "view == mongoExplorer",
|
"when": "view == mongoExplorer && resource == mongoServer",
|
||||||
"group": "navigation"
|
"group": "navigation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mongo.connect",
|
||||||
|
"when": "view == mongoExplorer && resource == mongoDb",
|
||||||
|
"group": "navigation"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"commandPalette": [
|
||||||
|
{
|
||||||
|
"command": "mongo.connect",
|
||||||
|
"when": "view == mongoExplorer && resource == mongoDb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
{
|
{
|
||||||
"command": "mongo.execute",
|
"command": "mongo.execute",
|
||||||
"key": "shift+f8"
|
"key": "cmd+`",
|
||||||
},
|
"when": "resourceLangId==mongo"
|
||||||
{
|
|
||||||
"command": "mongo.executeLine",
|
|
||||||
"key": "f8"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"configuration": {
|
"configuration": {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||||
|
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||||
|
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon fill="#C5C5C5" points="12,3 8,3 8,4 11,4 11,7 14,7 14,14 6,14 6,8 5,8 5,15 15,15 15,6"/><path fill="#89D185" d="M7 3.018h-2v-2.018h-1.981v2.018h-2.019v1.982h2.019v2h1.981v-2h2v-1.982z"/></svg>
|
После Ширина: | Высота: | Размер: 419 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#2D2D30"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#C5C5C5"/></svg>
|
После Ширина: | Высота: | Размер: 986 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><polygon points="13,2 8,2 6,2 6,0 2,0 2,2 0,2 0,6 2,6 2,8 4,8 4,16 16,16 16,5" fill="#F6F6F6"/><polygon points="12,3 8,3 8,4 11,4 11,7 14,7 14,14 6,14 6,8 5,8 5,15 15,15 15,6" fill="#424242"/><path d="M7 3.018h-2v-2.018h-1.981v2.018h-2.019v1.982h2.019v2h1.981v-2h2v-1.982z" fill="#388A34"/><polygon points="11,7 11,4 8,4 8,6 6,6 6,8 6,14 14,14 14,7" fill="#F0EFF1"/></svg>
|
После Ширина: | Высота: | Размер: 435 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#F6F6F6"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#424242"/></svg>
|
После Ширина: | Высота: | Размер: 986 B |
|
@ -2,31 +2,34 @@
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
import { MongoExplorer } from './mongo/explorer';
|
import { MongoExplorer } from './mongo/explorer';
|
||||||
import { MongoCommands, ResultDocument } from './mongo/commands';
|
import { MongoCommands } from './mongo/commands';
|
||||||
import { Model, Database, Server, IMongoResource } from './mongo/mongo';
|
import { Model, Database, Server, IMongoResource } from './mongo/mongo';
|
||||||
import MongoDBLanguageClient from './mongo/languageClient';
|
import MongoDBLanguageClient from './mongo/languageClient';
|
||||||
|
|
||||||
|
let connectedDb: Database = null;
|
||||||
|
let languageClient: MongoDBLanguageClient = null;
|
||||||
|
let model: Model;
|
||||||
|
let mongoDocumentCounter = 0;
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
|
|
||||||
const languageClient = new MongoDBLanguageClient(context);
|
|
||||||
|
|
||||||
// Create the storage folder
|
// Create the storage folder
|
||||||
if (context.storagePath) {
|
if (context.storagePath) {
|
||||||
createStorageFolder(context).then(() => {
|
createStorageFolder(context).then(() => {
|
||||||
const outputChannel = vscode.window.createOutputChannel('Mongo');
|
languageClient = new MongoDBLanguageClient(context);
|
||||||
const model = new Model({ extensionContext: context, outputChannel });
|
model = new Model(context.storagePath);
|
||||||
const resultDocument = new ResultDocument(context);
|
|
||||||
|
|
||||||
// Mongo Tree View
|
// Mongo Tree View
|
||||||
const treeDataProvider = new MongoExplorer(model);
|
const treeDataProvider = new MongoExplorer(model);
|
||||||
const treeView = vscode.window.createTreeView('mongoExplorer', treeDataProvider);
|
const view = vscode.window.createExplorerView('mongoExplorer', 'Mongo', treeDataProvider);
|
||||||
context.subscriptions.push(treeView);
|
context.subscriptions.push(view);
|
||||||
const disposable = treeDataProvider.onChange((node) => treeView.refresh(node));
|
const disposable = treeDataProvider.onChange((node) => view.refresh(node));
|
||||||
context.subscriptions.push(new vscode.Disposable(() => disposable.dispose()))
|
context.subscriptions.push(new vscode.Disposable(() => disposable.dispose()))
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('mongo.addServer', () => { MongoCommands.addServer(model) }));
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.addServer', () => addServer()));
|
||||||
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.refreshExplorer', () => view.refresh(model)));
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('mongo.removeServer', (element: IMongoResource) => {
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.removeServer', (element: IMongoResource) => {
|
||||||
if (element instanceof Server) {
|
if (element instanceof Server) {
|
||||||
model.remove(element.id);
|
model.remove(element.id);
|
||||||
|
@ -34,34 +37,62 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
model.remove(element.server.id);
|
model.remove(element.server.id);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('mongo.resource.onClick', (element: IMongoResource) => {
|
|
||||||
if (element instanceof Database) {
|
vscode.window.setStatusBarMessage('Mongo: Not connected');
|
||||||
languageClient.connect(element);
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.connect', (element: Database) => connectToDatabase(element)));
|
||||||
MongoCommands.openShell(element);
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.connectDb', () => {
|
||||||
}
|
vscode.window.showQuickPick(getDatabaseQuickPicks()).then(pick => connectToDatabase(pick.database));
|
||||||
}));
|
}));
|
||||||
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.newScrapbook', (element: IMongoResource) => {
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('mongo.execute', () => MongoCommands.executeScript(model, resultDocument, outputChannel, true)));
|
if (element instanceof Database) {
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('mongo.executeLine', () => MongoCommands.executeScript(model, resultDocument, outputChannel, false)));
|
connectToDatabase(element);
|
||||||
|
|
||||||
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor((editor => {
|
|
||||||
if (editor) {
|
|
||||||
const database = MongoCommands.getDatabaseForDocument(editor.document, model);
|
|
||||||
if (database) {
|
|
||||||
vscode.window.setStatusBarMessage('Connected to ' + database.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})));
|
let uri = vscode.Uri.file(path.join(vscode.workspace.rootPath, `Scrapbook-${++mongoDocumentCounter}.mongo`));
|
||||||
|
uri = uri.with({ scheme: 'untitled' });
|
||||||
|
vscode.workspace.openTextDocument(uri)
|
||||||
|
.then(textDocument => vscode.window.showTextDocument(textDocument));
|
||||||
|
}));
|
||||||
|
context.subscriptions.push(vscode.commands.registerCommand('mongo.execute', () => MongoCommands.executeScript(connectedDb)));
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
context.subscriptions.push(vscode.window.createTreeView('mongoExplorer', {
|
|
||||||
provideRootNode(): any {
|
|
||||||
vscode.window.showInformationMessage('Open a workspace first.')
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addServer(): void {
|
||||||
|
vscode.window.showInputBox({
|
||||||
|
placeHolder: 'mongodb://host:port'
|
||||||
|
}).then(value => {
|
||||||
|
if (value) {
|
||||||
|
model.add(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseQuickPick implements vscode.QuickPickItem {
|
||||||
|
readonly label: string;
|
||||||
|
readonly description: string;
|
||||||
|
constructor(readonly database: Database) {
|
||||||
|
this.label = database.label;
|
||||||
|
this.description = database.server.label + '/' + database.label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDatabaseQuickPicks(): Thenable<DatabaseQuickPick[]> {
|
||||||
|
const quickPicks: DatabaseQuickPick[] = [];
|
||||||
|
return model.getChildren().then(servers => {
|
||||||
|
return Promise.all(servers.map(server => server.getChildren()))
|
||||||
|
.then(allDatabases => {
|
||||||
|
allDatabases.forEach(databases => {
|
||||||
|
quickPicks.push(...databases.map(database => new DatabaseQuickPick(<Database>database)));
|
||||||
|
});
|
||||||
|
return quickPicks;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectToDatabase(database: Database): void {
|
||||||
|
connectedDb = database;
|
||||||
|
languageClient.connect(database);
|
||||||
|
vscode.window.setStatusBarMessage('Mongo: Connected to ' + database.server.host + '/' + connectedDb.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createStorageFolder(context: vscode.ExtensionContext): Promise<void> {
|
async function createStorageFolder(context: vscode.ExtensionContext): Promise<void> {
|
||||||
|
|
|
@ -3,103 +3,35 @@ import * as vscode from 'vscode';
|
||||||
import { Model, Server, Database } from './mongo';
|
import { Model, Server, Database } from './mongo';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
export class ResultDocument implements vscode.TextDocumentContentProvider {
|
|
||||||
|
|
||||||
private _result: Map<string, string> = new Map<string, any>();
|
|
||||||
|
|
||||||
private _onDidChange: vscode.EventEmitter<vscode.Uri> = new vscode.EventEmitter<vscode.Uri>();
|
|
||||||
public readonly onDidChange: vscode.Event<vscode.Uri> = this._onDidChange.event;
|
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
|
||||||
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider('mongo', this));
|
|
||||||
}
|
|
||||||
|
|
||||||
provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult<string> {
|
|
||||||
const result = this._result.get(uri.toString())
|
|
||||||
return result ? result : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setResult(uri: vscode.Uri, result: string) {
|
|
||||||
this._result.set(uri.toString(), result);
|
|
||||||
this._onDidChange.fire(uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MongoCommands {
|
export class MongoCommands {
|
||||||
|
|
||||||
public static addServer(model: Model): void {
|
public static executeScript(database: Database): void {
|
||||||
vscode.window.showInputBox({
|
if (!database) {
|
||||||
placeHolder: 'mongodb://host:port'
|
vscode.window.showErrorMessage('Please connect to the database first');
|
||||||
}).then(value => {
|
return;
|
||||||
if (value) {
|
|
||||||
model.add(value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static openShell(database: Database): void {
|
|
||||||
let uri = vscode.Uri.file(path.join(vscode.workspace.rootPath, database.server.host + '_' + database.server.port + '_' + database.label + '.mongo'));
|
|
||||||
const exists = fs.existsSync(uri.fsPath);
|
|
||||||
if (!exists) {
|
|
||||||
uri = uri.with({ scheme: 'untitled' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activeEditor = vscode.window.activeTextEditor;
|
||||||
|
if (activeEditor.document.languageId !== 'mongo') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = activeEditor.document.lineAt(activeEditor.selection.start.line).text;
|
||||||
|
let uri = vscode.Uri.file(path.join(vscode.workspace.rootPath, 'result.json'));
|
||||||
|
uri = uri.with({ scheme: 'untitled' });
|
||||||
vscode.workspace.openTextDocument(uri)
|
vscode.workspace.openTextDocument(uri)
|
||||||
.then(textDocument => {
|
.then(textDocument => vscode.window.showTextDocument(textDocument, vscode.ViewColumn.Two, true))
|
||||||
return vscode.window.showTextDocument(textDocument)
|
.then(editor => {
|
||||||
.then(editor => {
|
database.executeScript(text)
|
||||||
if (!exists && !MongoCommands.isShellDocument(textDocument, database)) {
|
.then(result => {
|
||||||
editor.edit(builder => {
|
editor.edit(editorBuilder => {
|
||||||
builder.insert(new vscode.Position(0, 0), database.connectionString + '\n');
|
if (editor.document.lineCount > 0) {
|
||||||
});
|
const lastLine = editor.document.lineAt(editor.document.lineCount - 1);
|
||||||
}
|
editorBuilder.delete(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(lastLine.range.start.line, lastLine.range.end.character)));
|
||||||
|
}
|
||||||
|
editorBuilder.insert(new vscode.Position(0, 0), result);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static executeScript(model: Model, resultDocument: ResultDocument, outputChannel: vscode.OutputChannel, selection: boolean): void {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (editor.document.languageId === 'mongo' || editor.document.uri.fsPath.endsWith('.mongo')) {
|
|
||||||
const text = selection ? MongoCommands.getSelectedText(editor) : editor.document.lineAt(editor.selection.start.line).text;
|
|
||||||
const database = MongoCommands.getDatabaseForDocument(editor.document, model);
|
|
||||||
if (database) {
|
|
||||||
database.executeScript(text)
|
|
||||||
.then(result => {
|
|
||||||
const uri = vscode.Uri.parse('mongo://test/result.json');
|
|
||||||
resultDocument.setResult(uri, result);
|
|
||||||
vscode.workspace.openTextDocument(uri)
|
|
||||||
.then(textDocument => {
|
|
||||||
vscode.window.showTextDocument(textDocument, vscode.ViewColumn.Two, true);
|
|
||||||
});
|
|
||||||
outputChannel.append(result);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
vscode.window.showErrorMessage('Please connect to the database first');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static getSelectedText(editor: vscode.TextEditor): string {
|
|
||||||
const selection = editor.selection;
|
|
||||||
if (selection.start.isEqual(selection.end)) {
|
|
||||||
editor.document.getText();
|
|
||||||
}
|
|
||||||
return editor.document.getText(selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getDatabaseForDocument(document: vscode.TextDocument, model: Model) {
|
|
||||||
if (document.languageId === 'mongo' || document.uri.fsPath.endsWith('.mongo')) {
|
|
||||||
for (const server of model.servers) {
|
|
||||||
for (const database of server.databases) {
|
|
||||||
if (MongoCommands.isShellDocument(document, database)) {
|
|
||||||
return database;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static isShellDocument(document: vscode.TextDocument, database: Database): boolean {
|
|
||||||
return database.connectionString === document.lineAt(0).text;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -32,6 +32,10 @@ export class MongoExplorer implements TreeDataProvider<IMongoResource> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getContextKey(node: IMongoResource): string {
|
||||||
|
return node.contextKey;
|
||||||
|
}
|
||||||
|
|
||||||
resolveChildren(node: IMongoResource): Thenable<IMongoResource[]> {
|
resolveChildren(node: IMongoResource): Thenable<IMongoResource[]> {
|
||||||
const disposables = this._disposables.get(node);
|
const disposables = this._disposables.get(node);
|
||||||
if (disposables) {
|
if (disposables) {
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as cp from 'child_process';
|
import * as cp from 'child_process';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { MongoClient, Db, ReadPreference, Code, Server as MongoServer } from 'mongodb';
|
import { MongoClient, Db, ReadPreference, Code, Server as MongoServer, Collection as MongoCollection } from 'mongodb';
|
||||||
import { Shell } from './shell';
|
import { Shell } from './shell';
|
||||||
import { EventEmitter, Event, Command } from 'vscode';
|
import { EventEmitter, Event, Command } from 'vscode';
|
||||||
|
|
||||||
export interface IMongoContext {
|
|
||||||
extensionContext: vscode.ExtensionContext;
|
|
||||||
outputChannel: vscode.OutputChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMongoResource {
|
export interface IMongoResource {
|
||||||
label: string;
|
label: string;
|
||||||
type: string;
|
|
||||||
getChildren?(): Thenable<IMongoResource[]>;
|
getChildren?(): Thenable<IMongoResource[]>;
|
||||||
onChange?: Event<void>
|
onChange?: Event<void>
|
||||||
|
contextKey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServersJson {
|
class ServersJson {
|
||||||
|
|
||||||
private _filePath: string;
|
private _filePath: string;
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
constructor(storagePath: string) {
|
||||||
this._filePath = context.storagePath + '/servers.json';
|
this._filePath = storagePath + '/servers.json';
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<string[]> {
|
async load(): Promise<string[]> {
|
||||||
|
@ -66,8 +61,8 @@ export class Model implements IMongoResource {
|
||||||
private _onChange: EventEmitter<void> = new EventEmitter<void>();
|
private _onChange: EventEmitter<void> = new EventEmitter<void>();
|
||||||
readonly onChange: Event<void> = this._onChange.event;
|
readonly onChange: Event<void> = this._onChange.event;
|
||||||
|
|
||||||
constructor(private context: IMongoContext) {
|
constructor(storagePath: string) {
|
||||||
this._serversJson = new ServersJson(context.extensionContext);
|
this._serversJson = new ServersJson(storagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildren(): Promise<IMongoResource[]> {
|
getChildren(): Promise<IMongoResource[]> {
|
||||||
|
@ -105,18 +100,18 @@ export class Model implements IMongoResource {
|
||||||
private resolveServer(connectionString: string): Promise<Server> {
|
private resolveServer(connectionString: string): Promise<Server> {
|
||||||
return <Promise<Server>>MongoClient.connect(connectionString)
|
return <Promise<Server>>MongoClient.connect(connectionString)
|
||||||
.then(db => {
|
.then(db => {
|
||||||
return new Server(connectionString, db.serverConfig, this.context);
|
return new Server(connectionString, db.serverConfig);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Server implements IMongoResource {
|
export class Server implements IMongoResource {
|
||||||
|
|
||||||
readonly type: string = 'mongoServer';
|
readonly contextKey: string = 'mongoServer';
|
||||||
|
|
||||||
private _databases: Database[] = [];
|
private _databases: Database[] = [];
|
||||||
|
|
||||||
constructor(public readonly id: string, private readonly mongoServer: MongoServer, private context: IMongoContext) {
|
constructor(public readonly id: string, private readonly mongoServer: MongoServer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get host(): string {
|
get host(): string {
|
||||||
|
@ -137,7 +132,7 @@ export class Server implements IMongoResource {
|
||||||
return <Promise<IMongoResource[]>>MongoClient.connect(this.id)
|
return <Promise<IMongoResource[]>>MongoClient.connect(this.id)
|
||||||
.then(db => db.admin().listDatabases()
|
.then(db => db.admin().listDatabases()
|
||||||
.then((value: { databases: { name }[] }) => {
|
.then((value: { databases: { name }[] }) => {
|
||||||
this._databases = value.databases.map(database => new Database(database.name, this, this.context));
|
this._databases = value.databases.map(database => new Database(database.name, this));
|
||||||
db.close();
|
db.close();
|
||||||
return <IMongoResource[]>this._databases;
|
return <IMongoResource[]>this._databases;
|
||||||
}));
|
}));
|
||||||
|
@ -150,19 +145,26 @@ export class Server implements IMongoResource {
|
||||||
|
|
||||||
export class Database implements IMongoResource {
|
export class Database implements IMongoResource {
|
||||||
|
|
||||||
readonly type: string = 'mongoDb';
|
readonly contextKey: string = 'mongoDb';
|
||||||
readonly connectionString: string;
|
|
||||||
private shell: Shell;
|
private shell: Shell;
|
||||||
|
|
||||||
constructor(readonly id: string, readonly server: Server, private context: IMongoContext) {
|
constructor(readonly id: string, readonly server: Server) {
|
||||||
this.connectionString = '//connection:' + this.server.id + '/' + this.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get label(): string {
|
get label(): string {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly canHaveChildren: boolean = false;
|
readonly canHaveChildren: boolean = true;
|
||||||
|
|
||||||
|
getChildren(): Promise<IMongoResource[]> {
|
||||||
|
return <Promise<IMongoResource[]>>this.getDb().then(db => {
|
||||||
|
return db.collections().then(collections => {
|
||||||
|
return collections.map(collection => new Collection(collection));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getDb(): Promise<Db> {
|
getDb(): Promise<Db> {
|
||||||
const uri = vscode.Uri.parse(this.server.id);
|
const uri = vscode.Uri.parse(this.server.id);
|
||||||
|
@ -223,4 +225,16 @@ export class Database implements IMongoResource {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Collection implements IMongoResource {
|
||||||
|
|
||||||
|
constructor(private collection: MongoCollection) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get label(): string {
|
||||||
|
return this.collection.collectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly canHaveChildren: boolean = false;
|
||||||
}
|
}
|
|
@ -524,34 +524,26 @@ declare module 'vscode' {
|
||||||
|
|
||||||
export namespace window {
|
export namespace window {
|
||||||
|
|
||||||
/**
|
|
||||||
* Show window-wide progress, e.g. in the status bar, for the provided task. The task is
|
|
||||||
* considering running as long as the promise it returned isn't resolved or rejected.
|
|
||||||
*
|
|
||||||
* @param task A function callback that represents a long running operation.
|
|
||||||
*/
|
|
||||||
export function withWindowProgress<R>(title: string, task: (progress: Progress<string>, token: CancellationToken) => Thenable<R>): Thenable<R>;
|
|
||||||
|
|
||||||
export function sampleFunction(): Thenable<any>;
|
export function sampleFunction(): Thenable<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace window {
|
export namespace window {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new [TreeView](#TreeView) instance.
|
* Create a new explorer view.
|
||||||
*
|
*
|
||||||
* @param viewId A unique id that identifies the view.
|
* @param id View id.
|
||||||
* @param provider A [TreeDataProvider](#TreeDataProvider).
|
* @param name View name.
|
||||||
* @return An instance of [TreeView](#TreeView).
|
* @param dataProvider A [TreeDataProvider](#TreeDataProvider).
|
||||||
|
* @return An instance of [View](#View).
|
||||||
*/
|
*/
|
||||||
export function createTreeView<T>(viewId: string, provider: TreeDataProvider<T>): TreeView<T>;
|
export function createExplorerView<T>(id: string, name: string, dataProvider: TreeDataProvider<T>): View<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An source control is able to provide [resource states](#SourceControlResourceState)
|
* A view to interact with nodes
|
||||||
* to the editor and interact with the editor in several source control related ways.
|
|
||||||
*/
|
*/
|
||||||
export interface TreeView<T> {
|
export interface View<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the given nodes
|
* Refresh the given nodes
|
||||||
|
@ -610,6 +602,14 @@ declare module 'vscode' {
|
||||||
*/
|
*/
|
||||||
getHasChildren?(node: T): boolean;
|
getHasChildren?(node: T): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider a context key to be set for the node. This can be used to describe actions for each node.
|
||||||
|
*
|
||||||
|
* @param node The node from which the provider computes context key.
|
||||||
|
* @return A context key.
|
||||||
|
*/
|
||||||
|
getContextKey?(node: T): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the command to execute when `node` is clicked.
|
* Get the command to execute when `node` is clicked.
|
||||||
*
|
*
|
||||||
|
|
Загрузка…
Ссылка в новой задаче