mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 09:35:37 -05:00
Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)
This commit is contained in:
@@ -17,6 +17,8 @@ import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocum
|
||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
|
||||
export class BoundModelReferenceCollection {
|
||||
|
||||
@@ -69,6 +71,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private readonly _textFileService: ITextFileService;
|
||||
private readonly _fileService: IFileService;
|
||||
private readonly _untitledEditorService: IUntitledEditorService;
|
||||
private readonly _environmentService: IWorkbenchEnvironmentService;
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||
@@ -85,12 +88,14 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this._modelService = modelService;
|
||||
this._textModelResolverService = textModelResolverService;
|
||||
this._textFileService = textFileService;
|
||||
this._fileService = fileService;
|
||||
this._untitledEditorService = untitledEditorService;
|
||||
this._environmentService = environmentService;
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
this._modelIsSynced = {};
|
||||
@@ -214,10 +219,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
}
|
||||
|
||||
private _handleUntitledScheme(uri: URI): Promise<boolean> {
|
||||
const asFileUri = uri.with({ scheme: Schemas.file });
|
||||
return this._fileService.resolve(asFileUri).then(stats => {
|
||||
const asLocalUri = toLocalResource(uri, this._environmentService.configuration.remoteAuthority);
|
||||
return this._fileService.resolve(asLocalUri).then(stats => {
|
||||
// don't create a new file ontop of an existing file
|
||||
return Promise.reject(new Error('file already exists on disk'));
|
||||
return Promise.reject(new Error('file already exists'));
|
||||
}, err => {
|
||||
return this._doCreateUntitled(uri).then(resource => !!resource);
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
namespace delta {
|
||||
|
||||
@@ -330,12 +331,12 @@ export class MainThreadDocumentsAndEditors {
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IPanelService panelService: IPanelService
|
||||
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService);
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService);
|
||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||
|
||||
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileSer
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
@@ -105,10 +106,6 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
// --- forwarding calls
|
||||
|
||||
private static _asBuffer(data: Uint8Array): Buffer {
|
||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
}
|
||||
|
||||
stat(resource: URI): Promise<IStat> {
|
||||
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
|
||||
throw err;
|
||||
@@ -116,11 +113,11 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
}
|
||||
|
||||
readFile(resource: URI): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(this._handle, resource);
|
||||
return this._proxy.$readFile(this._handle, resource).then(buffer => buffer.buffer);
|
||||
}
|
||||
|
||||
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
||||
return this._proxy.$writeFile(this._handle, resource, RemoteFileSystemProvider._asBuffer(content), opts);
|
||||
return this._proxy.$writeFile(this._handle, resource, VSBuffer.wrap(content), opts);
|
||||
}
|
||||
|
||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
@@ -153,12 +150,12 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
|
||||
data.set(readData, offset);
|
||||
data.set(readData.buffer, offset);
|
||||
return readData.byteLength;
|
||||
});
|
||||
}
|
||||
|
||||
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$write(this._handle, fd, pos, Buffer.from(data, offset, length));
|
||||
return this._proxy.$write(this._handle, fd, pos, VSBuffer.wrap(data).slice(offset, offset + length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
// Nothing
|
||||
@@ -256,8 +257,9 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
const source = new CancellationTokenSource();
|
||||
const editorOrModel = findEditor(model, this._codeEditorService) || model;
|
||||
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', overrides);
|
||||
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, model, FormattingMode.Silent, source.token);
|
||||
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, editorOrModel, FormattingMode.Silent, source.token);
|
||||
|
||||
setTimeout(() => {
|
||||
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
|
||||
|
||||
@@ -3,47 +3,55 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
||||
export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
|
||||
private readonly _entries: { [id: number]: IDisposable };
|
||||
private readonly entries: Map<number, { accessor: IStatusbarEntryAccessor, alignment: MainThreadStatusBarAlignment, priority: number }> = new Map();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IStatusbarService private readonly _statusbarService: IStatusbarService
|
||||
) {
|
||||
this._entries = Object.create(null);
|
||||
}
|
||||
_extHostContext: IExtHostContext,
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService
|
||||
) { }
|
||||
|
||||
dispose(): void {
|
||||
for (const key in this._entries) {
|
||||
this._entries[key].dispose();
|
||||
}
|
||||
this.entries.forEach(entry => entry.accessor.dispose());
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
||||
const entry = { text, tooltip, command, color, extensionId };
|
||||
|
||||
// Dispose any old
|
||||
this.$dispose(id);
|
||||
// Reset existing entry if alignment or priority changed
|
||||
let existingEntry = this.entries.get(id);
|
||||
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
|
||||
dispose(existingEntry.accessor);
|
||||
this.entries.delete(id);
|
||||
existingEntry = undefined;
|
||||
}
|
||||
|
||||
// Add new
|
||||
const entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
|
||||
this._entries[id] = entry;
|
||||
// Create new entry if not existing
|
||||
if (!existingEntry) {
|
||||
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, alignment, priority), alignment, priority });
|
||||
}
|
||||
|
||||
// Otherwise update
|
||||
else {
|
||||
existingEntry.accessor.update(entry);
|
||||
}
|
||||
}
|
||||
|
||||
$dispose(id: number) {
|
||||
const disposeable = this._entries[id];
|
||||
if (disposeable) {
|
||||
disposeable.dispose();
|
||||
const entry = this.entries.get(id);
|
||||
if (entry) {
|
||||
dispose(entry.accessor);
|
||||
this.entries.delete(id);
|
||||
}
|
||||
|
||||
delete this._entries[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,22 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape } from '../common/extHost.protocol';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||
export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
private readonly proxy: ExtHostWindowShape;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@ITunnelService private readonly tunnelService: ITunnelService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow);
|
||||
|
||||
@@ -29,13 +34,54 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
|
||||
for (const tunnel of this._tunnels.values()) {
|
||||
tunnel.then(tunnel => tunnel.dispose());
|
||||
}
|
||||
this._tunnels.clear();
|
||||
}
|
||||
|
||||
$getWindowVisibility(): Promise<boolean> {
|
||||
return this.windowService.isFocused();
|
||||
}
|
||||
|
||||
$openUri(uri: UriComponents): Promise<boolean> {
|
||||
return this.windowsService.openExternal(URI.revive(uri).toString(true));
|
||||
async $openUri(uriComponent: UriComponents): Promise<boolean> {
|
||||
const uri = URI.revive(uriComponent);
|
||||
if (!!this.environmentService.configuration.remoteAuthority) {
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
const port = this.getLocalhostPort(uri);
|
||||
if (typeof port === 'number') {
|
||||
const tunnel = await this.getOrCreateTunnel(port);
|
||||
if (tunnel) {
|
||||
const tunneledUrl = uri.toString().replace(
|
||||
new RegExp(`^${uri.scheme}://localhost:${port}/`),
|
||||
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`);
|
||||
return this.windowsService.openExternal(tunneledUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.windowsService.openExternal(uri.toString(true));
|
||||
}
|
||||
|
||||
private getLocalhostPort(uri: URI): number | undefined {
|
||||
const match = /^localhost:(\d+)$/.exec(uri.authority);
|
||||
if (match) {
|
||||
return +match[1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
const existing = this._tunnels.get(remotePort);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const tunnel = this.tunnelService.openTunnel(remotePort);
|
||||
if (tunnel) {
|
||||
this._tunnels.set(remotePort, tunnel);
|
||||
}
|
||||
return tunnel;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user