Merge VS Code 1.26.1 (#2394)

* Squash merge commits for 1.26 (#1) (#2323)

* Polish tag search as per feedback (#55269)

* Polish tag search as per feedback

* Updated regex

* Allow users to opt-out of features that send online requests in the background (#55097)

* settings sweep #54690

* Minor css tweaks to enable eoverflow elipsis in more places (#55277)

* fix an issue with titlebarheight when not scaling with zoom

* Settings descriptions update #54690

* fixes #55209

* Settings editor - many padding fixes

* More space above level 2 label

* Fixing Cannot debug npm script using Yarn #55103

* Settings editor - show ellipsis when description overflows

* Settings editor - ... fix measuring around links, relayout

* Setting descriptions

* Settings editor - fix ... for some short lines, fix select container width

* Settings editor - overlay trees so scrollable shadow is full width

* Fix #54133 - missing extension settings after reload

* Settings color token description tweak

* Settings editor - disable overflow indicator temporarily, needs to be faster

* Added command to Run the selected npm script

* fixes #54452

* fixes #54929

* fixes #55248

* prefix command with extension name

* Contribute run selected to the context menu

* node-debug@1.26.6

* Allow terminal rendererType to be swapped out at runtime

Part of #53274
Fixes #55344

* Settings editor - fix not focusing search when restoring editor
setInput must be actually async. Will be fixed naturally when we aren't using winJS promises...

* Settings editor - TOC should only expand the section with a selected item

* Bump node-debug2

* Settings editor - Tree focus outlines

* Settings editor - don't blink the scrollbar when toc selection changes
And hide TOC correctly when the editor is narrow

* Settings editor - header rows should not be selectable

* fixes #54877

* change debug assignee to isi

* Settings sweep (#54690)

* workaround for #55051

* Settings sweep (#54690)

* settings sweep

#54690

* Don't try closing tags when you type > after another >

* Describe what implementation code lens does

Fixes #55370

* fix javadoc formatter setting description

* fixes #55325

* update to officical TS version

* Settings editor - Even more padding, use semibold instead of bold

* Fix #55357 - fix TOC twistie

* fixes #55288

* explorer: refresh on di change file system provider registration

fixes #53256

* Disable push to Linux repo to test standalone publisher

* New env var to notify log level to extensions #54001

* Disable snippets in extension search (when not in suggest dropdown) (#55281)

* Disable snippits in extension search (when not in suggest dropdown)

* Add monaco input contributions

* Fix bug preventing snippetSuggestions from taking effect in sub-editors

* Latest emmet helper to fix #52366

* Fix comment updates for threads within same file

* Allow extensions to log telemetry to log files #54001

* Pull latest css grammar

* files.exclude control - use same style for "add" vs "edit"

* files.exclude control - focus/keyboard behavior

* don't show menubar too early

* files.exclude - better styling

* Place cursor at end of extensions search box on autofill (#55254)

* Place cursor at end of extensions search box on autofill

* Use position instead of selection

* fix linux build issue (empty if block)

* Settings editor - fix extension category prefixes

* Settings editor - add simple ellipsis for first line that overflows, doesn't cover case when first line does not overflow but there is more text, TODO

* File/Text search provider docs

* Fixes #52655

* Include epoch (#55008)

* Fixes #53385

* Fixes #49480

*  VS Code Insiders (Users) not opening Fixes #55353

* Better handling of the case when the extension host fails to start

* Fixes #53966

*  Remove confusing Start from wordPartLeft commands ID

* vscode-xterm@3.6.0-beta12

Fixes #55488

* Initial size is set to infinity!! Fixes #55461

* Polish embeddedEditorBackground

* configuration service misses event

* Fix #55224 - fix duplicate results in multiroot workspace from splitting the diskseach query

* Select all not working in issue reporter on mac, fixes #55424

* Disable fuzzy matching for extensions autosuggest (#55498)

* Fix clipping of extensions search border in some third party themes (#55504)

* fixes #55538

* Fix bug causing an aria alert to not be shown the third time
 (and odd numbers thereafter)

* Settings editor - work around rendering glitch with webkit-line-clamp

* Settings editor - revert earlier '...' changes

* Settings editor - move enumDescription to its own div, because it disturbs -webkit-line-clamp for some reason

* Settings editor - better overflow indicator

* Don't show existing filters in autocomplete (#55495)

* Dont show existing filters in autocomplete

* Simplify

* Settings Editor: Add aria labels for input elements Fixes: #54836 (#55543)

* fixes #55223

* Update vscode-css-languageservice to 3.0.10-next.1

* Fix #55509 - settings navigation

* Fix #55519

* Fix #55520

* FIx #55524

* Fix #55556 - include wordSeparators in all search queries, so findTextInFiles can respect isWordMatch correctly

* oss updates for endgame

* Fix unit tests

* fixes #55522

* Avoid missing manifest error from bubbling up #54757

* Settings format crawl

* Search provider - Fix FileSearchProvider to return array, not progress

* Fix #55598

* Settings editor - fix NPE rendering settings with no description

* dont render inden guides in search box (#55600)

* fixes #55454

* More settings crawl

* Another change for #55598 - maxResults applies to FileSearch and TextSearch but not FileIndex

* Fix FileSearchProvider unit tests for progress change

* fixes #55561

* Settings description update for #54690

* Update setting descriptions for online services

* Minor edits

* fixes #55513

* fixes #55451

* Fix #55612 - fix findTextInFiles cancellation

* fixes #55539

* More setting description tweaks

* Setting to disable online experiments #54354

* fixes #55507

* fixes #55515

* Show online services action only in Insiders for now

* Settings editor - change toc behavior default to 'filter'

* Settings editor - nicer filter count style during search

* Fix #55617 - search viewlet icons

* Settings editor - better styling for element count indicator

* SearchProvider - fix NPE when searching extraFileResources

* Allow extends to work without json suffix

Fixes #16905

* Remove accessability options logic entirely

Follow up on #55451

* use latest version of DAP

* fixes #55490

* fixes #55122

* fixes #52332

* Avoid assumptions about git: URIs (fixes #36236)

* relative path for descriptions

* resourece: get rid of isFile context key

fixes #48275

* Register previous ids for compatibility (#53497)

* more tuning for #48275

* no need to always re-read "files explorer"

fixes #52003

* read out active composites properly

fixes #51967

* Update link colors for hc theme to meet color contrast ratio, fixes #55651

Also updated link color for `textLinkActiveForeground` to be the same as `textLinkForeground` as it wasn't properly updated

* detect 'winpty-agent.exe'; fixes #55672

* node-debug@1.26.7

* reset counter on new label

* Settings editor - fix multiple setting links in one description

* Settings editor - color code blocks in setting descriptions, fix #55532

* Settings editor - hover color in TOC

* Settings editor - fix navigation NPE

* Settings editor - fix text control width

* Settings editor - maybe fix #55684

* Fix bug causing cursor to not move on paste

* fixes #53582

* Use ctrlCmd instead of ctrl for go down from search box

* fixes #55264

* fixes #55456

* filter for spcaes before triggering search (#55611)

* Fix #55698 - don't lose filtered TOC counts when refreshing TOC

* fixes #55421

* fixes #28979

* fixes #55576

* only add check for updates to windows/linux help

* readonly files: append decoration to label

fixes #53022

* debug: do not show toolbar while initialising

fixes #55026

* Opening launch.json should not activate debug extensions

fixes #55029

* fixes #55435

* fixes #55434

* fixes #55439

* trigger menu only on altkey up

* Fix #50555 - fix settings editor memory leak

* Fix #55712 - no need to focus 'a' anymore when restoring control focus after tree render

* fixes #55335

* proper fix for readonly model

fixes #53022

* improve FoldingRangeKind spec (for #55686)

* Use class with static fields (fixes #55494)

* Fixes #53671

* fixes #54630

* [html] should disable ionic suggestions by default. Currently forces deprecated Ionic v1 suggestions in .html files while typing. Fixes #53324

* cleanup deps

* debug issues back to andre

* update electron for smoketest

* Fix #55757 - prevent settings tabs from overflowing

* Fix #53897 - revert setting menu defaults to old editor

* Add enum descriptions to `typescript.preferences.importModuleSpecifier`

* Fix #55767 - leaking style elements from settings editor

* Fix #55521 - prevent flashing when clicking in exclude control

* Update Git modified color for contrast ratio, fixes #53140

* Revert "Merge branch 'master' of github.com:Microsoft/vscode"

This reverts commit bf46b6bfbae0cab99c2863e1244a916181fa9fbc, reversing
changes made to e275a424483dfb4ed33b428c97d5e2c441d6b917.

* Revert "Revert "Merge branch 'master' of github.com:Microsoft/vscode""

This reverts commit 53949d963f39e40757557c6526332354a31d9154.

* don't ask to install an incomplete menu

* Fix NPE in terminal AccessibilityManager

Fixes #55744

* don't display fallback menu unless we've closed the last window

* fixes #55547

* Fix smoke tests for extension search box

* Update OSSREADME.json for Electron 2.0.5

* Update distro

Includes Chromium license changes

* fix #55455

* fix #55865

* fixes #55893

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation (#55805)

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation

* ONly show on @recommended or @recommended:workspace

* Make more consistant

* Fix #55911

* Understand json activity (#55926)

* Understand json file activity

* Refactoring

* adding composer.json

* Distro update for experiments

* use terminal.processId for auto-attach; fixes #55918

* Reject invalid URI with vscode.openFolder (for #55891)

* improve win32 setup system vs user detection

fixes #55840

fixes #55840

delay winreg import

related to #55840

show notification earlier

related to #55840

fix #55840

update inno setup message

related to #55840

* Fix #55593 - this code only operates on local paths, so use fsPath and Uri.file instead

* Bring back the old menu due to electron 2.0 issues (#55913)

* add the old menu back for native menus

* make menu labels match

* `vscode.openFolder`: treat missing URI schema gracefully (for #55891)

* delay EH reattach; fixes #55955

* Mark all json files under appSettingsHome as settings

* Use localized strings for telemetry opt-out

* Exception when saving file editor opened from remote file provider (fixes #55051)

* Remove terminal menu from stable

Fixes 56003

* VSCode Insiders crashes on open with TypeError: Cannot read property 'lastIndexOf' of undefined. Fixes #54933

* improve fix for #55891

* fix #55916

* Improve #55891

* increase EH debugging restart delay; fixes #55955

* Revert "Don't include non-resource entries in history quick pick"

This reverts commit 37209a838e9f7e9abe6dc53ed73cdf1e03b72060.

* Diff editor: horizontal scrollbar height is smaller (fixes #56062)

* improve openFolder uri fix (correctly treat backslashes)

* fixes #56116
repair ipc for native menubar keybindings

* Fix #56240 - Open the JSON settings editor instead of the UI editor

* Fix #55536

* uriDisplay: if no formatter is registered fall back to getPathlabel

fixes #56104

* VSCode hangs when opening python file. Fixes #56377

* VS Code Hangs When Opening Specific PowerShell File. Fixes #56430

* Fix #56433 - search extraFileResources even when no folders open

* Workaround #55649

* Fix in master #56371

* Fix tests #56371

* Fix in master #56317

* increase version to 1.26.1

* Fixes #56387: Handle SIGPIPE in extension host

* fixes #56185

* Fix merge issues (part 1)

* Fix build breaks (part 1)

* Build breaks (part 2)

* Build breaks (part 3)

* More build breaks (part 4)

* Fix build breaks (part 5)

* WIP

* Fix menus

* Render query result and message panels (#2363)

* Put back query editor hot exit changes

* Fix grid changes that broke profiler (#2365)

* Update APIs for saving query editor state

* Fix restore view state for profiler and edit data

* Updating custom default themes to support 4.5:1 contrast ratio

* Test updates

* Fix Extension Manager and Windows Setup

* Update license headers

* Add appveyor and travis files back

* Fix hidden modal dropdown issue
This commit is contained in:
Karl Burtram
2018-09-04 14:55:00 -07:00
committed by GitHub
parent 3763278366
commit 81329fa7fa
2638 changed files with 118456 additions and 64012 deletions

View File

@@ -53,6 +53,7 @@ import './mainThreadTerminalService';
import './mainThreadTreeViews';
import './mainThreadLogService';
import './mainThreadWebview';
import './mainThreadComments';
import './mainThreadUrls';
import './mainThreadWindow';
import './mainThreadWorkspace';

View File

@@ -94,11 +94,11 @@ function _generateMarkdown(description: string | ICommandHandlerDescription): st
parts.push('\n\n');
if (description.args) {
for (let arg of description.args) {
parts.push(`* _${arg.name}_ ${arg.description || ''}\n`);
parts.push(`* _${arg.name}_ - ${arg.description || ''}\n`);
}
}
if (description.returns) {
parts.push(`* _(returns)_ ${description.returns}`);
parts.push(`* _(returns)_ - ${description.returns}`);
}
parts.push('\n\n');
return parts.join('');

View File

@@ -0,0 +1,156 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditor, isCodeEditor, isDiffEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import * as modes from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { keys } from 'vs/base/common/map';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../node/extHost.protocol';
import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService';
import { COMMENTS_PANEL_ID } from 'vs/workbench/parts/comments/electron-browser/commentsPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import URI from 'vs/base/common/uri';
import { ReviewController } from 'vs/workbench/parts/comments/electron-browser/commentsEditorContribution';
@extHostNamedCustomer(MainContext.MainThreadComments)
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
private _disposables: IDisposable[];
private _proxy: ExtHostCommentsShape;
private _documentProviders = new Map<number, IDisposable>();
private _workspaceProviders = new Map<number, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@IEditorService private _editorService: IEditorService,
@ICommentService private _commentService: ICommentService,
@IPanelService private _panelService: IPanelService,
@ICodeEditorService private _codeEditorService: ICodeEditorService
) {
super();
this._disposables = [];
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
this._disposables.push(this._editorService.onDidActiveEditorChange(e => {
const editors = this.getFocusedEditors();
if (!editors || !editors.length) {
return;
}
editors.forEach(editor => {
const controller = ReviewController.get(editor);
if (!controller) {
return;
}
if (!editor.getModel()) {
return;
}
const outerEditorURI = editor.getModel().uri;
this.provideDocumentComments(outerEditorURI).then(commentInfos => {
this._commentService.setDocumentComments(outerEditorURI, commentInfos.filter(info => info !== null));
});
});
}));
}
$registerDocumentCommentProvider(handle: number): void {
this._documentProviders.set(handle, undefined);
this._commentService.registerDataProvider(
handle,
{
provideDocumentComments: async (uri, token) => {
return this._proxy.$provideDocumentComments(handle, uri);
},
onDidChangeCommentThreads: null,
createNewCommentThread: async (uri, range, text, token) => {
return this._proxy.$createNewCommentThread(handle, uri, range, text);
},
replyToCommentThread: async (uri, range, thread, text, token) => {
return this._proxy.$replyToCommentThread(handle, uri, range, thread, text);
}
}
);
}
$registerWorkspaceCommentProvider(handle: number): void {
this._workspaceProviders.set(handle, undefined);
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, true);
this._panelService.openPanel(COMMENTS_PANEL_ID);
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
if (commentThreads) {
this._commentService.setWorkspaceComments(handle, commentThreads);
}
});
}
$unregisterDocumentCommentProvider(handle: number): void {
this._documentProviders.delete(handle);
this._commentService.unregisterDataProvider(handle);
}
$unregisterWorkspaceCommentProvider(handle: number): void {
this._workspaceProviders.delete(handle);
if (this._workspaceProviders.size === 0) {
this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, false);
}
this._commentService.removeWorkspaceComments(handle);
}
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) {
// notify comment service
this._commentService.updateComments(event);
}
dispose(): void {
this._disposables = dispose(this._disposables);
this._workspaceProviders.forEach(value => dispose(value));
this._workspaceProviders.clear();
this._documentProviders.forEach(value => dispose(value));
this._documentProviders.clear();
}
getFocusedEditors(): ICodeEditor[] {
let activeControl = this._editorService.activeControl;
if (activeControl) {
if (isCodeEditor(activeControl.getControl())) {
return [this._editorService.activeControl.getControl() as ICodeEditor];
}
if (isDiffEditor(activeControl.getControl())) {
let diffEditor = activeControl.getControl() as IDiffEditor;
return [diffEditor.getOriginalEditor(), diffEditor.getModifiedEditor()];
}
}
let editor = this._codeEditorService.getFocusedCodeEditor();
if (editor) {
return [editor];
}
return [];
}
async provideWorkspaceComments(): Promise<modes.CommentThread[]> {
const result: modes.CommentThread[] = [];
for (const handle of keys(this._workspaceProviders)) {
result.push(...await this._proxy.$provideWorkspaceComments(handle));
}
return result;
}
async provideDocumentComments(resource: URI): Promise<modes.CommentInfo[]> {
const result: modes.CommentInfo[] = [];
for (const handle of keys(this._documentProviders)) {
result.push(await this._proxy.$provideDocumentComments(handle, resource));
}
return result;
}
}

View File

@@ -14,12 +14,13 @@ import { TPromise } from 'vs/base/common/winjs.base';
import {
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto
} from '../node/extHost.protocol';
} from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import severity from 'vs/base/common/severity';
import { AbstractDebugAdapter, convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/node/debugAdapter';
import { AbstractDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
import * as paths from 'vs/base/common/paths';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils';
@extHostNamedCustomer(MainContext.MainThreadDebugService)
@@ -38,9 +39,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
this._toDispose = [];
this._toDispose.push(debugService.onDidNewProcess(proc => this._proxy.$acceptDebugSessionStarted(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.onDidEndProcess(proc => this._proxy.$acceptDebugSessionTerminated(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.getViewModel().onDidFocusProcess(proc => {
this._toDispose.push(debugService.onDidNewSession(proc => this._proxy.$acceptDebugSessionStarted(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.onDidEndSession(proc => this._proxy.$acceptDebugSessionTerminated(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
this._toDispose.push(debugService.getViewModel().onDidFocusSession(proc => {
if (proc) {
this._proxy.$acceptDebugSessionActiveChanged(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false));
} else {
@@ -50,7 +51,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
this._toDispose.push(debugService.onDidCustomEvent(event => {
if (event && event.sessionId) {
const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === event.sessionId).pop();
const process = this.debugService.getModel().getSessions().filter(p => p.getId() === event.sessionId).pop();
if (process) {
this._proxy.$acceptDebugSessionCustomEvent(event.sessionId, process.configuration.type, process.configuration.name, event);
}
@@ -63,15 +64,15 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this));
}
createDebugAdapter(debugType: string, adapterInfo): IDebugAdapter {
createDebugAdapter(debugType: string, adapterInfo, debugPort: number): IDebugAdapter {
const handle = this._debugAdaptersHandleCounter++;
const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo);
const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo, debugPort);
this._debugAdapters.set(handle, da);
return da;
}
substituteVariables(folder: IWorkspaceFolder, config: IConfig): TPromise<IConfig> {
return this._proxy.$substituteVariables(folder.uri, config);
return this._proxy.$substituteVariables(folder ? folder.uri : undefined, config);
}
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void> {
@@ -89,7 +90,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
// set up a handler to send more
this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => {
if (e) {
// Ignore session only breakpoint events since they should only reflect in the UI
if (e && !e.sessionOnly) {
const delta: IBreakpointsDeltaDto = {};
if (e.added) {
delta.added = this.convertToDto(e.added);
@@ -157,10 +159,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
type: 'function',
id: fbp.getId(),
enabled: fbp.enabled,
functionName: fbp.name,
hitCondition: bp.hitCondition,
// {{SQL CARBON EDIT}}
// condition: bp.condition
condition: fbp.condition,
hitCondition: fbp.hitCondition,
logMessage: fbp.logMessage,
functionName: fbp.name
};
} else {
const sbp = <IBreakpoint>bp;
@@ -220,9 +222,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): TPromise<any> {
const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === sessionId).pop();
const process = this.debugService.getModel().getSessions().filter(p => p.getId() === sessionId).pop();
if (process) {
return process.session.custom(request, args).then(response => {
return process.raw.custom(request, args).then(response => {
if (response && response.success) {
return response.body;
} else {
@@ -267,7 +269,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
/*
class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _debugType: string, private _adapterExecutable: IAdapterExecutable | null) {
constructor(private _handle: number, private _proxy: ExtHostDebugServiceShape, private _debugType: string, private _adapterExecutable: IAdapterExecutable | null, private _debugPort: number) {
super();
}
@@ -280,7 +282,7 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
}
public startSession(): TPromise<void> {
return this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable);
return this._proxy.$startDASession(this._handle, this._debugType, this._adapterExecutable, this._debugPort);
}
public sendMessage(message: DebugProtocol.ProtocolMessage): void {

View File

@@ -10,14 +10,14 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
import { TPromise } from 'vs/base/common/winjs.base';
import { values } from 'vs/base/common/collections';
import { CancellationToken } from 'vs/base/common/cancellation';
class DecorationRequestsQueue {
private _idPool = 0;
private _requests: { [id: number]: DecorationRequest } = Object.create(null);
private _resolver: { [id: number]: Function } = Object.create(null);
private _resolver: { [id: number]: (data: DecorationData) => any } = Object.create(null);
private _timer: number;
@@ -27,16 +27,18 @@ class DecorationRequestsQueue {
//
}
enqueue(handle: number, uri: URI): TPromise<DecorationData> {
enqueue(handle: number, uri: URI, token: CancellationToken): Promise<DecorationData> {
const id = ++this._idPool;
return new TPromise((resolve, reject) => {
const result = new Promise<DecorationData>(resolve => {
this._requests[id] = { id, handle, uri };
this._resolver[id] = resolve;
this._processQueue();
}, () => {
});
token.onCancellationRequested(() => {
delete this._requests[id];
delete this._resolver[id];
});
return result;
}
private _processQueue(): void {
@@ -87,8 +89,8 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
const registration = this._decorationsService.registerDecorationsProvider({
label,
onDidChange: emitter.event,
provideDecorations: (uri) => {
return this._requestQueue.enqueue(handle, uri).then(data => {
provideDecorations: (uri, token) => {
return this._requestQueue.enqueue(handle, uri, token).then(data => {
if (!data) {
return undefined;
}

View File

@@ -4,18 +4,20 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI, { UriComponents } from 'vs/base/common/uri';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable } from 'vs/base/common/lifecycle';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITextModel, DefaultEndOfLine } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { MainThreadDocumentContentProvidersShape, ExtHostContext, ExtHostDocumentContentProvidersShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { createTextBuffer } from 'vs/editor/common/model/textModel';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostDocumentContentProvidersShape, IExtHostContext, MainContext, MainThreadDocumentContentProvidersShape } from '../node/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadDocumentContentProviders)
export class MainThreadDocumentContentProviders implements MainThreadDocumentContentProvidersShape {
@@ -28,8 +30,8 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IEditorGroupService editorGroupService: IEditorGroupService
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
@ICodeEditorService codeEditorService: ICodeEditorService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentContentProviders);
}
@@ -69,10 +71,11 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
return;
}
const textBuffer = createTextBuffer(value, DefaultEndOfLine.CRLF);
if (!model.equalsTextBuffer(textBuffer)) {
model.setValueFromTextBuffer(textBuffer);
}
this._editorWorkerService.computeMoreMinimalEdits(model.uri, [{ text: value, range: model.getFullModelRange() }]).then(edits => {
if (edits.length > 0) {
// use the evil-edit as these models show in readonly-editor only
model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
}
}, onUnexpectedError);
}
}

View File

@@ -220,11 +220,18 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
return this._fileService.resolveFile(asFileUri).then(stats => {
// don't create a new file ontop of an existing file
return TPromise.wrapError<boolean>(new Error('file already exists on disk'));
}, err => this._doCreateUntitled(asFileUri).then(resource => !!resource));
}, err => {
return this._doCreateUntitled(uri).then(resource => !!resource);
});
}
private _doCreateUntitled(resource?: URI, modeId?: string, initialValue?: string): TPromise<URI> {
return this._untitledEditorService.loadOrCreate({ resource, modeId, initialValue }).then(model => {
return this._untitledEditorService.loadOrCreate({
resource,
modeId,
initialValue,
useResourcePath: Boolean(resource && resource.path)
}).then(model => {
const resource = model.getResource();
if (!this._modelIsSynced[resource.toString()]) {

View File

@@ -12,8 +12,9 @@ import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IModelAddedData, ITextEditorAddData, IDocumentsAndEditorsDelta, IExtHostContext, MainContext } from '../node/extHost.protocol';
import { MainThreadTextEditor } from './mainThreadEditor';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Position as EditorPosition, IEditor } from 'vs/platform/editor/common/editor';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/shared/editor';
import { IEditor } from 'vs/workbench/common/editor';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { MainThreadDocuments } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
@@ -21,9 +22,10 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { isCodeEditor, isDiffEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isDiffEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import URI from 'vs/base/common/uri';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
namespace mapset {
@@ -159,7 +161,7 @@ class MainThreadDocumentAndEditorStateComputer {
private readonly _onDidChangeState: (delta: DocumentAndEditorStateDelta) => void,
@IModelService private readonly _modelService: IModelService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IWorkbenchEditorService private readonly _workbenchEditorService: IWorkbenchEditorService
@IEditorService private readonly _editorService: IEditorService
) {
this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose);
this._modelService.onModelRemoved(this._updateState, this, this._toDispose);
@@ -177,8 +179,8 @@ class MainThreadDocumentAndEditorStateComputer {
private _onDidAddEditor(e: ICodeEditor): void {
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidChangeModel(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidFocusEditor(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidBlurEditor(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidFocusEditorText(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidBlurEditorText(() => this._updateState()));
this._updateState();
}
@@ -243,32 +245,26 @@ class MainThreadDocumentAndEditorStateComputer {
) {
const apiEditor = new TextEditorSnapshot(editor);
editors.set(apiEditor.id, apiEditor);
if (editor.isFocused()) {
if (editor.hasTextFocus()) {
activeEditor = apiEditor.id;
}
}
}
// active editor: if none of the previous editors had focus we try
// to match the action workbench editor with one of editor we have
// to match the active workbench editor with one of editor we have
// just computed
if (!activeEditor) {
const workbenchEditor = this._workbenchEditorService.getActiveEditor();
if (workbenchEditor) {
const workbenchEditorControl = workbenchEditor.getControl();
let candidate: ICodeEditor;
if (isCodeEditor(workbenchEditorControl)) {
candidate = workbenchEditorControl;
} else if (isDiffEditor(workbenchEditorControl)) {
candidate = workbenchEditorControl.getModifiedEditor();
}
if (candidate) {
editors.forEach(snapshot => {
if (candidate === snapshot.editor) {
activeEditor = snapshot.id;
}
});
}
let candidate = this._editorService.activeTextEditorWidget;
if (isDiffEditor(candidate)) {
candidate = candidate.getModifiedEditor();
}
if (candidate) {
editors.forEach(snapshot => {
if (candidate === snapshot.editor) {
activeEditor = snapshot.id;
}
});
}
}
@@ -304,24 +300,26 @@ export class MainThreadDocumentsAndEditors {
extHostContext: IExtHostContext,
@IModelService private readonly _modelService: IModelService,
@ITextFileService private readonly _textFileService: ITextFileService,
@IWorkbenchEditorService private readonly _workbenchEditorService: IWorkbenchEditorService,
@IEditorService private readonly _editorService: IEditorService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IModeService modeService: IModeService,
@IFileService fileService: IFileService,
@ITextModelService textModelResolverService: ITextModelService,
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
@IEditorGroupService editorGroupService: IEditorGroupService
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IBulkEditService bulkEditService: IBulkEditService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService);
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, this._workbenchEditorService, editorGroupService, textModelResolverService, fileService, this._modelService);
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
// It is expected that the ctor of the state computer calls our `_onDelta`.
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, _workbenchEditorService);
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService);
this._toDispose = [
mainThreadDocuments,
@@ -423,10 +421,10 @@ export class MainThreadDocumentsAndEditors {
};
}
private _findEditorPosition(editor: MainThreadTextEditor): EditorPosition {
for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn {
for (let workbenchEditor of this._editorService.visibleControls) {
if (editor.matches(workbenchEditor)) {
return workbenchEditor.position;
return editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
}
}
return undefined;

View File

@@ -6,7 +6,7 @@
import * as editorCommon from 'vs/editor/common/editorCommon';
import { Event, Emitter } from 'vs/base/common/event';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IEditor } from 'vs/workbench/common/editor';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Range, IRange } from 'vs/editor/common/core/range';
@@ -266,10 +266,10 @@ export class MainThreadTextEditor {
this.setCodeEditor(null);
}));
this._codeEditorListeners.push(this._codeEditor.onDidFocusEditor(() => {
this._codeEditorListeners.push(this._codeEditor.onDidFocusEditorWidget(() => {
this._focusTracker.onGainedFocus();
}));
this._codeEditorListeners.push(this._codeEditor.onDidBlurEditor(() => {
this._codeEditorListeners.push(this._codeEditor.onDidBlurEditorWidget(() => {
this._focusTracker.onLostFocus();
}));
@@ -423,7 +423,7 @@ export class MainThreadTextEditor {
public isFocused(): boolean {
if (this._codeEditor) {
return this._codeEditor.isFocused();
return this._codeEditor.hasTextFocus();
}
return false;
}
@@ -448,9 +448,9 @@ export class MainThreadTextEditor {
}
if (opts.setEndOfLine === EndOfLine.CRLF) {
this._model.setEOL(EndOfLineSequence.CRLF);
this._model.pushEOL(EndOfLineSequence.CRLF);
} else if (opts.setEndOfLine === EndOfLine.LF) {
this._model.setEOL(EndOfLineSequence.LF);
this._model.pushEOL(EndOfLineSequence.LF);
}
let transformedEdits = edits.map((edit): IIdentifiedSingleEditOperation => {

View File

@@ -4,35 +4,37 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI, { UriComponents } from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { localize } from 'vs/nls';
import { disposed } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDecorationRenderOptions, IDecorationOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { MainThreadTextEditor } from './mainThreadEditor';
import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { equals as objectEquals } from 'vs/base/common/objects';
import { ExtHostContext, MainThreadTextEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext } from '../node/extHost.protocol';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { BulkEdit } from 'vs/editor/browser/services/bulkEdit';
import { IModelService } from 'vs/editor/common/services/modelService';
import { isCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { isResourceFileEdit } from 'vs/editor/common/modes';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { EditorViewColumn, viewColumnToEditorGroup, editorGroupToViewColumn } from 'vs/workbench/api/shared/editor';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IApplyEditsOptions, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { ExtHostContext, ExtHostEditorsShape, IExtHostContext, ITextDocumentShowOptions, ITextEditorPositionData, MainThreadTextEditorsShape } from '../node/extHost.protocol';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from './mainThreadEditor';
import { IOpenerService } from 'vs/platform/opener/common/opener';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
private static INSTANCE_COUNT: number = 0;
private _instanceId: string;
private _proxy: ExtHostEditorsShape;
private _documentsAndEditors: MainThreadDocumentsAndEditors;
private _workbenchEditorService: IWorkbenchEditorService;
private _toDispose: IDisposable[];
private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
private _editorPositionData: ITextEditorPositionData;
@@ -42,15 +44,13 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
documentsAndEditors: MainThreadDocumentsAndEditors,
extHostContext: IExtHostContext,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
@IEditorGroupService editorGroupService: IEditorGroupService,
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IFileService private readonly _fileService: IFileService,
@IModelService private readonly _modelService: IModelService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@IEditorService private readonly _editorService: IEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService
) {
this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT);
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
this._documentsAndEditors = documentsAndEditors;
this._workbenchEditorService = workbenchEditorService;
this._toDispose = [];
this._textEditorsListenersMap = Object.create(null);
this._editorPositionData = null;
@@ -58,8 +58,9 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
this._toDispose.push(documentsAndEditors.onTextEditorAdd(editors => editors.forEach(this._onTextEditorAdd, this)));
this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this)));
this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors()));
this._toDispose.push(editorGroupService.onEditorGroupMoved(() => this._updateActiveAndVisibleTextEditors()));
this._toDispose.push(this._editorService.onDidVisibleEditorsChange(() => this._updateActiveAndVisibleTextEditors()));
this._toDispose.push(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors()));
this._toDispose.push(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors()));
this._registeredDecorationTypes = Object.create(null);
}
@@ -103,10 +104,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
private _getTextEditorPositionData(): ITextEditorPositionData {
let result: ITextEditorPositionData = Object.create(null);
for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
for (let workbenchEditor of this._editorService.visibleControls) {
const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
if (id) {
result[id] = workbenchEditor.position;
result[id] = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
}
}
return result;
@@ -128,7 +129,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
options: editorOptions
};
return this._workbenchEditorService.openEditor(input, options.position).then(editor => {
return this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position)).then(editor => {
if (!editor) {
return undefined;
}
@@ -136,14 +137,14 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
});
}
$tryShowEditor(id: string, position: EditorPosition): TPromise<void> {
$tryShowEditor(id: string, position?: EditorViewColumn): TPromise<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let model = mainThreadEditor.getModel();
return this._workbenchEditorService.openEditor({
return this._editorService.openEditor({
resource: model.uri,
options: { preserveFocus: false }
}, position).then(() => { return; });
}, viewColumnToEditorGroup(this._editorGroupService, position)).then(() => { return; });
}
return undefined;
}
@@ -151,10 +152,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
$tryHideEditor(id: string): TPromise<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let editors = this._workbenchEditorService.getVisibleEditors();
let editors = this._editorService.visibleControls;
for (let editor of editors) {
if (mainThreadEditor.matches(editor)) {
return this._workbenchEditorService.closeEditor(editor.position, editor.input).then(() => { return; });
return editor.group.closeEditor(editor.input).then(() => { return; });
}
}
}
@@ -170,6 +171,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<void> {
key = `${this._instanceId}-${key}`;
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
}
@@ -178,6 +180,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
$trySetDecorationsFast(id: string, key: string, ranges: number[]): TPromise<void> {
key = `${this._instanceId}-${key}`;
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError(disposed(`TextEditor(${id})`));
}
@@ -209,31 +212,8 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): TPromise<boolean> {
const { edits } = reviveWorkspaceEditDto(dto);
// First check if loaded models were not changed in the meantime
for (let i = 0, len = edits.length; i < len; i++) {
const edit = edits[i];
if (!isResourceFileEdit(edit) && edit.modelVersionId) {
let model = this._modelService.getModel(edit.resource);
if (model && model.getVersionId() !== edit.modelVersionId) {
// model changed in the meantime
return TPromise.as(false);
}
}
}
let codeEditor: ICodeEditor;
let editor = this._workbenchEditorService.getActiveEditor();
if (editor) {
let candidate = editor.getControl();
if (isCodeEditor(candidate)) {
codeEditor = candidate;
}
}
return BulkEdit.perform(edits, this._textModelResolverService, this._fileService, codeEditor).then(() => true);
return this._bulkEditService.apply({ edits }, undefined).then(() => true, err => false);
}
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
@@ -244,11 +224,13 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
key = `${this._instanceId}-${key}`;
this._registeredDecorationTypes[key] = true;
this._codeEditorService.registerDecorationType(key, options);
}
$removeTextEditorDecorationType(key: string): void {
key = `${this._instanceId}-${key}`;
delete this._registeredDecorationTypes[key];
this._codeEditorService.removeDecorationType(key);
}
@@ -272,3 +254,46 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return TPromise.as(diffEditor.getLineChanges());
}
}
// --- commands
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const [resource, options, position] = args;
if (options || typeof position === 'number') {
// use editor options or editor view column as a hint to use the editor service for opening
return editorService.openEditor({ resource, options }, viewColumnToEditorGroup(editorGroupService, position)).then(_ => void 0);
}
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return TPromise.as(void 0);
}
// finally, delegate to opener service
return openerService.open(resource).then(_ => void 0);
});
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
let [leftResource, rightResource, label, description, options, position] = args;
if (!options || typeof options !== 'object') {
options = {
preserveFocus: false
};
}
if (!label) {
label = localize('diffLeftRightLabel', "{0} ⟷ {1}", leftResource.toString(true), rightResource.toString(true));
}
return editorService.openEditor({ leftResource, rightResource, label, description, options }, viewColumnToEditorGroup(editorGroupService, position)).then(() => void 0);
});

View File

@@ -5,10 +5,10 @@
'use strict';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions } from 'vs/platform/files/common/files';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../node/extHost.protocol';
@@ -71,11 +71,9 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
watch(resource: URI, opts: IWatchOptions) {
const session = Math.random();
this._proxy.$watch(this._handle, session, resource, opts);
return {
dispose: () => {
this._proxy.$unwatch(this._handle, session);
}
};
return toDisposable(() => {
this._proxy.$unwatch(this._handle, session);
});
}
$onFileSystemChange(changes: IFileChangeDto[]): void {
@@ -107,8 +105,8 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
return this._proxy.$writeFile(this._handle, resource, encoded, opts);
}
delete(resource: URI): TPromise<void, any> {
return this._proxy.$delete(this._handle, resource);
delete(resource: URI, opts: FileDeleteOptions): TPromise<void, any> {
return this._proxy.$delete(this._handle, resource, opts);
}
mkdir(resource: URI): TPromise<void, any> {

View File

@@ -4,29 +4,32 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
import { ExtHostContext, ExtHostFileSystemEventServiceShape, FileSystemEvents, IExtHostContext } from '../node/extHost.protocol';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/common/files';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../node/extHost.protocol';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
@extHostCustomer
export class MainThreadFileSystemEventService {
private readonly _listener: IDisposable;
private readonly _listener = new Array<IDisposable>();
constructor(
extHostContext: IExtHostContext,
@IFileService fileService: IFileService
@IFileService fileService: IFileService,
@ITextFileService textfileService: ITextFileService,
) {
const proxy: ExtHostFileSystemEventServiceShape = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
// file system events - (changes the editor and other make)
const events: FileSystemEvents = {
created: [],
changed: [],
deleted: []
};
this._listener = fileService.onFileChanges(event => {
fileService.onFileChanges(event => {
for (let change of event.changes) {
switch (change.type) {
case FileChangeType.ADDED:
@@ -45,10 +48,22 @@ export class MainThreadFileSystemEventService {
events.created.length = 0;
events.changed.length = 0;
events.deleted.length = 0;
});
}, undefined, this._listener);
// file operation events - (changes the editor makes)
fileService.onAfterOperation(e => {
if (e.operation === FileOperation.MOVE) {
proxy.$onFileRename(e.resource, e.target.resource);
}
}, undefined, this._listener);
textfileService.onWillMove(e => {
let promise = proxy.$onWillRename(e.oldResource, e.newResource);
e.waitUntil(promise);
}, undefined, this._listener);
}
dispose(): void {
this._listener.dispose();
dispose(this._listener);
}
}

View File

@@ -9,19 +9,20 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import * as search from 'vs/workbench/parts/search/common/search';
import { wireCancellationToken } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, SymbolInformationDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter } from '../node/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto } from '../node/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import URI from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
@@ -71,17 +72,31 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
private static _reviveSymbolInformationDto(data: SymbolInformationDto): modes.SymbolInformation;
private static _reviveSymbolInformationDto(data: SymbolInformationDto[]): modes.SymbolInformation[];
private static _reviveSymbolInformationDto(data: SymbolInformationDto | SymbolInformationDto[]): modes.SymbolInformation | modes.SymbolInformation[] {
private static _reviveDefinitionLinkDto(data: DefinitionLinkDto): modes.DefinitionLink;
private static _reviveDefinitionLinkDto(data: DefinitionLinkDto[]): modes.DefinitionLink[];
private static _reviveDefinitionLinkDto(data: DefinitionLinkDto | DefinitionLinkDto[]): modes.DefinitionLink | modes.DefinitionLink[] {
if (!data) {
return <modes.SymbolInformation>data;
return <modes.DefinitionLink>data;
} else if (Array.isArray(data)) {
data.forEach(MainThreadLanguageFeatures._reviveSymbolInformationDto);
return <modes.SymbolInformation[]>data;
data.forEach(l => MainThreadLanguageFeatures._reviveDefinitionLinkDto(l));
return <modes.DefinitionLink[]>data;
} else {
data.uri = URI.revive(data.uri);
return <modes.DefinitionLink>data;
}
}
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto): search.IWorkspaceSymbol;
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto[]): search.IWorkspaceSymbol[];
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[]): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] {
if (!data) {
return <search.IWorkspaceSymbol>data;
} else if (Array.isArray(data)) {
data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto);
return <search.IWorkspaceSymbol[]>data;
} else {
data.location = MainThreadLanguageFeatures._reviveLocationDto(data.location);
return <modes.SymbolInformation>data;
return <search.IWorkspaceSymbol>data;
}
}
@@ -96,10 +111,11 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- outline
$registerOutlineSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentSymbolProvider>{
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri)).then(MainThreadLanguageFeatures._reviveSymbolInformationDto);
$registerOutlineSupport(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
displayName,
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.DocumentSymbol[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri));
}
});
}
@@ -123,7 +139,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
provider.onDidChange = emitter.event;
}
this._registrations[handle] = modes.CodeLensProviderRegistry.register(toLanguageSelector(selector), provider);
this._registrations[handle] = modes.CodeLensProviderRegistry.register(typeConverters.LanguageSelector.from(selector), provider);
}
$emitCodeLensEvent(eventHandle: number, event?: any): void {
@@ -136,25 +152,25 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- declaration
$registerDeclaractionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DefinitionProviderRegistry.register(toLanguageSelector(selector), <modes.DefinitionProvider>{
provideDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
this._registrations[handle] = modes.DefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DefinitionProvider>{
provideDefinition: (model, position, token): Thenable<modes.DefinitionLink[]> => {
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ImplementationProviderRegistry.register(toLanguageSelector(selector), <modes.ImplementationProvider>{
this._registrations[handle] = modes.ImplementationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ImplementationProvider>{
provideImplementation: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(toLanguageSelector(selector), <modes.TypeDefinitionProvider>{
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.TypeDefinitionProvider>{
provideTypeDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveDefinitionLinkDto);
}
});
}
@@ -162,7 +178,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- extra info
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.HoverProviderRegistry.register(toLanguageSelector(selector), <modes.HoverProvider>{
this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.HoverProvider>{
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.Hover> => {
return wireCancellationToken(token, this._proxy.$provideHover(handle, model.uri, position));
}
@@ -172,7 +188,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- occurrences
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentHighlightProvider>{
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentHighlightProvider>{
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentHighlights(handle, model.uri, position));
}
@@ -182,7 +198,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- references
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ReferenceProviderRegistry.register(toLanguageSelector(selector), <modes.ReferenceProvider>{
this._registrations[handle] = modes.ReferenceProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ReferenceProvider>{
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> => {
return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context)).then(MainThreadLanguageFeatures._reviveLocationDto);
}
@@ -192,9 +208,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- quick fix
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(toLanguageSelector(selector), <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, range: EditorRange, context: modes.CodeActionContext, token: CancellationToken): Thenable<modes.CodeAction[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range, context))).then(MainThreadLanguageFeatures._reviveCodeActionDto);
this._registrations[handle] = modes.CodeActionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Thenable<modes.CodeAction[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context))).then(MainThreadLanguageFeatures._reviveCodeActionDto);
},
providedCodeActionKinds
});
@@ -203,7 +219,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- formatting
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentFormattingEditProvider>{
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options));
}
@@ -211,7 +227,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentRangeFormattingEditProvider>{
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options));
}
@@ -219,7 +235,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[]): void {
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.OnTypeFormattingEditProvider>{
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.OnTypeFormattingEditProvider>{
autoFormatTriggerCharacters,
@@ -233,18 +249,18 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerNavigateTypeSupport(handle: number): void {
let lastResultId: number;
this._registrations[handle] = WorkspaceSymbolProviderRegistry.register(<IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<modes.SymbolInformation[]> => {
this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<search.IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => {
if (lastResultId !== undefined) {
this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);
}
lastResultId = result._id;
return MainThreadLanguageFeatures._reviveSymbolInformationDto(result.symbols);
return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);
});
},
resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise<modes.SymbolInformation> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveSymbolInformationDto(i));
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol): TPromise<search.IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i));
}
});
}
@@ -253,7 +269,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportResolveLocation: boolean): void {
this._registrations[handle] = modes.RenameProviderRegistry.register(toLanguageSelector(selector), <modes.RenameProvider>{
this._registrations[handle] = modes.RenameProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.RenameProvider>{
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)).then(reviveWorkspaceEditDto);
},
@@ -266,7 +282,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- suggest
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
this._registrations[handle] = modes.SuggestRegistry.register(toLanguageSelector(selector), <modes.ISuggestSupport>{
this._registrations[handle] = modes.SuggestRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ISuggestSupport>{
triggerCharacters,
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable<modes.ISuggestResult> => {
return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position, context)).then(result => {
@@ -289,7 +305,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- parameter hints
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], triggerCharacter: string[]): void {
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(toLanguageSelector(selector), <modes.SignatureHelpProvider>{
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.SignatureHelpProvider>{
signatureHelpTriggerCharacters: triggerCharacter,
@@ -303,7 +319,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- links
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.LinkProviderRegistry.register(toLanguageSelector(selector), <modes.LinkProvider>{
this._registrations[handle] = modes.LinkProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.LinkProvider>{
provideLinks: (model, token) => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideDocumentLinks(handle, model.uri)));
},
@@ -317,7 +333,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
const proxy = this._proxy;
this._registrations[handle] = modes.ColorProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentColorProvider>{
this._registrations[handle] = modes.ColorProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentColorProvider>{
provideDocumentColors: (model, token) => {
return wireCancellationToken(token, proxy.$provideDocumentColors(handle, model.uri))
.then(documentColors => {
@@ -351,7 +367,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
const proxy = this._proxy;
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(toLanguageSelector(selector), <modes.FoldingRangeProvider>{
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.FoldingRangeProvider>{
provideFoldingRanges: (model, context, token) => {
return wireCancellationToken(token, proxy.$provideFoldingRanges(handle, model.uri, context));
}

View File

@@ -14,7 +14,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { once } from 'vs/base/common/event';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { dispose } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadMessageService)
@@ -24,8 +23,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
extHostContext: IExtHostContext,
@INotificationService private readonly _notificationService: INotificationService,
@ICommandService private readonly _commandService: ICommandService,
@IDialogService private readonly _dialogService: IDialogService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService
@IDialogService private readonly _dialogService: IDialogService
) {
//
}
@@ -79,7 +77,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
}
const secondaryActions: IAction[] = [];
if (extension && extension.extensionFolderPath !== this._environmentService.extensionDevelopmentPath) {
if (extension && !extension.isUnderDevelopment) {
secondaryActions.push(new ManageExtensionAction(extension.id, nls.localize('manageExtension', "Manage Extension"), this._commandService));
}

View File

@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IProgressService2, IProgress, IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import { IProgress } from 'vs/platform/progress/common/progress';
import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IProgressService2, IProgressStep, IProgressOptions } from 'vs/workbench/services/progress/common/progress';
@extHostNamedCustomer(MainContext.MainThreadProgress)
export class MainThreadProgress implements MainThreadProgressShape {

View File

@@ -6,41 +6,42 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { asWinJsPromise } from 'vs/base/common/async';
import { IQuickOpenService, IPickOptions, IInputOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput } from 'vs/platform/quickinput/common/quickInput';
import { InputBoxOptions } from 'vscode';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, TransferQuickPickItems, MainContext, IExtHostContext, TransferQuickInput, TransferQuickInputButton } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import URI from 'vs/base/common/uri';
interface QuickInputSession {
input: IQuickInput;
handlesToItems: Map<number, TransferQuickPickItems>;
}
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private _proxy: ExtHostQuickOpenShape;
private _quickOpenService: IQuickOpenService;
private _quickInputService: IQuickInputService;
private _doSetItems: (items: MyQuickPickItems[]) => any;
private _doSetItems: (items: TransferQuickPickItems[]) => any;
private _doSetError: (error: Error) => any;
private _contents: TPromise<MyQuickPickItems[]>;
private _contents: TPromise<TransferQuickPickItems[]>;
private _token: number = 0;
constructor(
extHostContext: IExtHostContext,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostQuickOpen);
this._quickOpenService = quickOpenService;
this._quickInputService = quickInputService;
}
public dispose(): void {
}
$show(options: IPickOptions): TPromise<number | number[]> {
$show(options: IPickOptions<TransferQuickPickItems>): TPromise<number | number[]> {
const myToken = ++this._token;
this._contents = new TPromise<MyQuickPickItems[]>((c, e) => {
this._contents = new TPromise<TransferQuickPickItems[]>((c, e) => {
this._doSetItems = (items) => {
if (myToken === this._token) {
c(items);
@@ -54,32 +55,33 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
});
if (options.canSelectMany) {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options, token)).then(items => {
options = {
...options,
onDidFocus: el => {
if (el) {
this._proxy.$onItemSelected((<TransferQuickPickItems>el).handle);
}
}
};
if (options.canPickMany) {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
if (items) {
return items.map(item => item.handle);
}
return undefined;
}, undefined, progress => {
if (progress) {
this._proxy.$onItemSelected((<MyQuickPickItems>progress).handle);
}
});
} else {
return asWinJsPromise(token => this._quickOpenService.pick(this._contents, options, token)).then(item => {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options, token)).then(item => {
if (item) {
return item.handle;
}
return undefined;
}, undefined, progress => {
if (progress) {
this._proxy.$onItemSelected((<MyQuickPickItems>progress).handle);
}
});
}
}
$setItems(items: MyQuickPickItems[]): TPromise<any> {
$setItems(items: TransferQuickPickItems[]): TPromise<any> {
if (this._doSetItems) {
this._doSetItems(items);
}
@@ -96,7 +98,6 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
// ---- input
$input(options: InputBoxOptions, validateInput: boolean): TPromise<string> {
const inputOptions: IInputOptions = Object.create(null);
if (options) {
@@ -116,4 +117,109 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
return asWinJsPromise(token => this._quickInputService.input(inputOptions, token));
}
// ---- QuickInput
private sessions = new Map<number, QuickInputSession>();
$createOrUpdate(params: TransferQuickInput): TPromise<void> {
const sessionId = params.id;
let session = this.sessions.get(sessionId);
if (!session) {
if (params.type === 'quickPick') {
const input = this._quickInputService.createQuickPick();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidChangeActive(items => {
this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidChangeSelection(items => {
this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
});
input.onDidChangeValue(value => {
this._proxy.$onDidChangeValue(sessionId, value);
});
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = {
input,
handlesToItems: new Map()
};
} else {
const input = this._quickInputService.createInputBox();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
});
input.onDidChangeValue(value => {
this._proxy.$onDidChangeValue(sessionId, value);
});
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = {
input,
handlesToItems: new Map()
};
}
this.sessions.set(sessionId, session);
}
const { input, handlesToItems } = session;
for (const param in params) {
if (param === 'id' || param === 'type') {
continue;
}
if (param === 'visible') {
if (params.visible) {
input.show();
} else {
input.hide();
}
} else if (param === 'items') {
handlesToItems.clear();
params[param].forEach(item => {
handlesToItems.set(item.handle, item);
});
input[param] = params[param];
} else if (param === 'activeItems' || param === 'selectedItems') {
input[param] = params[param]
.filter(handle => handlesToItems.has(handle))
.map(handle => handlesToItems.get(handle));
} else if (param === 'buttons') {
input[param] = params.buttons.map(button => {
if (button.handle === -1) {
return this._quickInputService.backButton;
}
const { iconPath, tooltip, handle } = button;
return {
iconPath: {
dark: URI.revive(iconPath.dark),
light: iconPath.light && URI.revive(iconPath.light)
},
tooltip,
handle
};
});
} else {
input[param] = params[param];
}
}
return TPromise.as(undefined);
}
$dispose(sessionId: number): TPromise<void> {
const session = this.sessions.get(sessionId);
if (session) {
session.input.dispose();
this.sessions.delete(sessionId);
}
return TPromise.as(undefined);
}
}

View File

@@ -401,17 +401,17 @@ export class MainThreadSCM implements MainThreadSCMShape {
}
if (enabled) {
repository.input.validateInput = async (value, pos): TPromise<IInputValidation | undefined> => {
const result = await this._proxy.$validateInput(sourceControlHandle, value, pos);
repository.input.validateInput = (value, pos): TPromise<IInputValidation | undefined> => {
return this._proxy.$validateInput(sourceControlHandle, value, pos).then(result => {
if (!result) {
return undefined;
}
if (!result) {
return undefined;
}
return {
message: result[0],
type: result[1]
};
return {
message: result[0],
type: result[1]
};
});
};
} else {
repository.input.validateInput = () => TPromise.as(undefined);

View File

@@ -16,7 +16,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { Position } from 'vs/editor/common/core/position';
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
import { getDocumentFormattingEdits, NoProviderError } from 'vs/editor/contrib/format/format';
import { EditOperationsCommand } from 'vs/editor/contrib/format/formatCommand';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../node/extHost.protocol';
@@ -24,20 +24,19 @@ import { EditOperation } from 'vs/editor/common/core/editOperation';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IProgressService2, ProgressLocation } from 'vs/workbench/services/progress/common/progress';
import { localize } from 'vs/nls';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IFileService } from 'vs/platform/files/common/files';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { CodeAction } from 'vs/editor/common/modes';
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
export interface ISaveParticipantParticipant extends ISaveParticipant {
// progressMessage: string;
@@ -93,7 +92,7 @@ function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): I
if (model.isAttachedToEditor()) {
for (const editor of codeEditorService.listCodeEditors()) {
if (editor.getModel() === model) {
if (editor.isFocused()) {
if (editor.hasTextFocus()) {
return editor; // favour focused editor if there are multiple
}
@@ -216,16 +215,20 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
const timeout = this._configurationService.getValue('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
return new Promise<ISingleEditOperation[]>((resolve, reject) => {
setTimeout(() => reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout)), timeout);
getDocumentFormattingEdits(model, { tabSize, insertSpaces })
.then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits))
.then(resolve, err => {
if (!(err instanceof Error) || err.name !== NoProviderError.Name) {
reject(err);
} else {
resolve();
}
});
let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces });
setTimeout(() => {
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
request.cancel();
}, timeout);
request.then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits)).then(resolve, err => {
if (!(err instanceof Error) || err.name !== NoProviderError.Name) {
reject(err);
} else {
resolve();
}
});
}).then(edits => {
if (!isFalsyOrEmpty(edits) && versionNow === model.getVersionId()) {
@@ -240,7 +243,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
}
private _editsWithEditor(editor: ICodeEditor, edits: ISingleEditOperation[]): void {
EditOperationsCommand.execute(editor, edits);
FormattingEdit.execute(editor, edits);
}
private _editWithModel(model: ITextModel, edits: ISingleEditOperation[]): void {
@@ -270,10 +273,8 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
class CodeActionOnParticipant implements ISaveParticipant {
constructor(
@ITextModelService private readonly _textModelService: ITextModelService,
@IFileService private readonly _fileService: IFileService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@ICommandService private readonly _commandService: ICommandService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IConfigurationService private readonly _configurationService: IConfigurationService
) { }
@@ -283,10 +284,6 @@ class CodeActionOnParticipant implements ISaveParticipant {
}
const model = editorModel.textEditorModel;
const editor = findEditor(model, this._codeEditorService);
if (!editor) {
return undefined;
}
const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() };
const setting = this._configurationService.getValue<ICodeActionsOnSaveOptions>('editor.codeActionsOnSave', settingsOverrides);
@@ -304,17 +301,20 @@ class CodeActionOnParticipant implements ISaveParticipant {
return new Promise<CodeAction[]>((resolve, reject) => {
setTimeout(() => reject(localize('codeActionsOnSave.didTimeout', "Aborted codeActionsOnSave after {0}ms", timeout)), timeout);
this.getActionsToRun(model, codeActionsOnSave).then(resolve);
}).then(actionsToRun => this.applyCodeActions(actionsToRun, editor));
}).then(actionsToRun => this.applyCodeActions(actionsToRun));
}
private async applyCodeActions(actionsToRun: CodeAction[], editor: ICodeEditor) {
private async applyCodeActions(actionsToRun: CodeAction[]) {
for (const action of actionsToRun) {
await applyCodeAction(action, this._textModelService, this._fileService, this._commandService, editor);
await applyCodeAction(action, this._bulkEditService, this._commandService);
}
}
private async getActionsToRun(model: ITextModel, codeActionsOnSave: CodeActionKind[]) {
const actions = await getCodeActions(model, model.getFullModelRange(), { kind: CodeActionKind.Source, includeSourceActions: true });
const actions = await getCodeActions(model, model.getFullModelRange(), {
type: 'auto',
filter: { kind: CodeActionKind.Source, includeSourceActions: true },
});
const actionsToRun = actions.filter(returnedAction => returnedAction.kind && codeActionsOnSave.some(onSaveKind => onSaveKind.contains(returnedAction.kind)));
return actionsToRun;
}

View File

@@ -5,11 +5,12 @@
'use strict';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import URI, { UriComponents } from 'vs/base/common/uri';
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { IFileMatch, ILineMatch, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType } from 'vs/platform/search/common/search';
import { TPromise } from 'vs/base/common/winjs.base';
import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType, SearchProviderType } from 'vs/platform/search/common/search';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol';
@@ -21,18 +22,27 @@ export class MainThreadSearch implements MainThreadSearchShape {
constructor(
extHostContext: IExtHostContext,
@ISearchService private readonly _searchService: ISearchService
@ISearchService private readonly _searchService: ISearchService,
@ITelemetryService private readonly _telemetryService: ITelemetryService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSearch);
}
dispose(): void {
this._searchProvider.forEach(value => dispose());
this._searchProvider.forEach(value => value.dispose());
this._searchProvider.clear();
}
$registerSearchProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, scheme, handle, this._proxy));
$registerTextSearchProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, SearchProviderType.text, scheme, handle, this._proxy));
}
$registerFileSearchProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, SearchProviderType.file, scheme, handle, this._proxy));
}
$registerFileIndexProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, SearchProviderType.fileIndex, scheme, handle, this._proxy));
}
$unregisterProvider(handle: number): void {
@@ -40,9 +50,17 @@ export class MainThreadSearch implements MainThreadSearchShape {
this._searchProvider.delete(handle);
}
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void {
$handleFileMatch(handle: number, session, data: UriComponents[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
$handleTextMatch(handle: number, session, data: IRawFileMatch2[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
$handleTelemetry(eventName: string, data: any): void {
this._telemetryService.publicLog(eventName, data);
}
}
class SearchOperation {
@@ -57,66 +75,57 @@ class SearchOperation {
//
}
addMatch(resource: URI, match: ILineMatch): void {
if (!this.matches.has(resource.toString())) {
this.matches.set(resource.toString(), { resource, lineMatches: [] });
addMatch(match: IFileMatch): void {
if (this.matches.has(match.resource.toString())) {
// Merge with previous IFileMatches
this.matches.get(match.resource.toString()).lineMatches.push(...match.lineMatches);
} else {
this.matches.set(match.resource.toString(), match);
}
if (match) {
this.matches.get(resource.toString()).lineMatches.push(match);
}
this.progress(this.matches.get(resource.toString()));
this.progress(this.matches.get(match.resource.toString()));
}
}
class RemoteSearchProvider implements ISearchResultProvider {
class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
private readonly _registrations: IDisposable[];
private readonly _searches = new Map<number, SearchOperation>();
constructor(
searchService: ISearchService,
type: SearchProviderType,
private readonly _scheme: string,
private readonly _handle: number,
private readonly _proxy: ExtHostSearchShape
) {
this._registrations = [searchService.registerSearchResultProvider(this)];
this._registrations = [searchService.registerSearchResultProvider(this._scheme, type, this)];
}
dispose(): void {
dispose(this._registrations);
}
search(query: ISearchQuery): PPromise<ISearchComplete, ISearchProgressItem> {
search(query: ISearchQuery, onProgress?: (p: ISearchProgressItem) => void): TPromise<ISearchComplete> {
if (isFalsyOrEmpty(query.folderQueries)) {
return PPromise.as(undefined);
}
let includes = { ...query.includePattern };
let excludes = { ...query.excludePattern };
for (const folderQuery of query.folderQueries) {
if (folderQuery.folder.scheme === this._scheme) {
includes = { ...includes, ...folderQuery.includePattern };
excludes = { ...excludes, ...folderQuery.excludePattern };
}
return TPromise.as(undefined);
}
let outer: TPromise;
return new PPromise((resolve, reject, report) => {
return new TPromise((resolve, reject) => {
const search = new SearchOperation(report);
const search = new SearchOperation(onProgress);
this._searches.set(search.id, search);
outer = query.type === QueryType.File
? this._proxy.$provideFileSearchResults(this._handle, search.id, query.filePattern)
: this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, { excludes: Object.keys(excludes), includes: Object.keys(includes) });
? this._proxy.$provideFileSearchResults(this._handle, search.id, query)
: this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, query);
outer.then(() => {
outer.then((result: ISearchCompleteStats) => {
this._searches.delete(search.id);
resolve(({ results: values(search.matches), stats: undefined }));
resolve(({ results: values(search.matches), stats: result.stats, limitHit: result.limitHit }));
}, err => {
this._searches.delete(search.id);
reject(err);
@@ -128,21 +137,28 @@ class RemoteSearchProvider implements ISearchResultProvider {
});
}
handleFindMatch(session: number, dataOrUri: UriComponents | [UriComponents, ILineMatch]): void {
clearCache(cacheKey: string): TPromise<void> {
return this._proxy.$clearCache(cacheKey);
}
handleFindMatch(session: number, dataOrUri: (UriComponents | IRawFileMatch2)[]): void {
if (!this._searches.has(session)) {
// ignore...
return;
}
let resource: URI;
let match: ILineMatch;
if (Array.isArray(dataOrUri)) {
resource = URI.revive(dataOrUri[0]);
match = dataOrUri[1];
} else {
resource = URI.revive(dataOrUri);
}
this._searches.get(session).addMatch(resource, match);
const searchOp = this._searches.get(session);
dataOrUri.forEach(result => {
if ((<IRawFileMatch2>result).lineMatches) {
searchOp.addMatch({
resource: URI.revive((<IRawFileMatch2>result).resource),
lineMatches: (<IRawFileMatch2>result).lineMatches
});
} else {
searchOp.addMatch({
resource: URI.revive(result)
});
}
});
}
}

View File

@@ -4,33 +4,34 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as crypto from 'crypto';
import * as nls from 'vs/nls';
import URI from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as Objects from 'vs/base/common/objects';
import { TPromise } from 'vs/base/common/winjs.base';
import * as Types from 'vs/base/common/types';
import * as Platform from 'vs/base/common/platform';
import { IStringDictionary } from 'vs/base/common/collections';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import {
ContributedTask, ExtensionTaskSourceTransfer, TaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
ContributedTask, ExtensionTaskSourceTransfer, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, TaskSourceKind, ExtensionTaskSource, RevealKind, PanelKind
} from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskService, TaskFilter } from 'vs/workbench/parts/tasks/common/taskService';
import { TaskDefinition } from 'vs/workbench/parts/tasks/node/tasks';
import { ITaskService, TaskFilter } from 'vs/workbench/parts/tasks/common/taskService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import {
TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO,
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO
} from 'vs/workbench/api/shared/tasks';
export { TaskDTO, TaskHandleDTO, TaskExecutionDTO, TaskFilterDTO };
namespace TaskExecutionDTO {
export function from(value: TaskExecution): TaskExecutionDTO {
return {
@@ -38,25 +39,46 @@ namespace TaskExecutionDTO {
task: TaskDTO.from(value.task)
};
}
export function to(value: TaskExecutionDTO, workspace: IWorkspaceContextService): TaskExecution {
export function to(value: TaskExecutionDTO, workspace: IWorkspaceContextService, executeOnly: boolean): TaskExecution {
return {
id: value.id,
task: TaskDTO.to(value.task, workspace)
task: TaskDTO.to(value.task, workspace, executeOnly)
};
}
}
namespace TaskProcessStartedDTO {
export function from(value: TaskExecution, processId: number): TaskProcessStartedDTO {
return {
id: value.id,
processId
};
}
}
namespace TaskProcessEndedDTO {
export function from(value: TaskExecution, exitCode: number): TaskProcessEndedDTO {
return {
id: value.id,
exitCode
};
}
}
namespace TaskDefinitionDTO {
export function from(value: TaskIdentifier): TaskDefinitionDTO {
export function from(value: KeyedTaskIdentifier): TaskDefinitionDTO {
let result = Objects.assign(Object.create(null), value);
delete result._key;
return result;
}
export function to(value: TaskDefinitionDTO): TaskIdentifier {
const hash = crypto.createHash('md5');
hash.update(JSON.stringify(value));
let result = Objects.assign(Object.create(null), value);
result._key = hash.digest('hex');
export function to(value: TaskDefinitionDTO, executeOnly: boolean): KeyedTaskIdentifier {
let result = TaskDefinition.createTaskIdentifier(value, console);
if (result === void 0 && executeOnly) {
result = {
_key: generateUuid(),
type: '$executeOnly'
};
}
return result;
}
}
@@ -288,7 +310,7 @@ namespace TaskDTO {
return result;
}
export function to(task: TaskDTO, workspace: IWorkspaceContextService): Task {
export function to(task: TaskDTO, workspace: IWorkspaceContextService, executeOnly: boolean): Task {
if (typeof task.name !== 'string') {
return undefined;
}
@@ -307,10 +329,10 @@ namespace TaskDTO {
let source = TaskSourceDTO.to(task.source, workspace);
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let definition = TaskDefinitionDTO.to(task.definition);
let definition = TaskDefinitionDTO.to(task.definition, executeOnly);
let id = `${task.source.extensionId}.${definition._key}`;
let result: ContributedTask = {
_id: id, // uuidMap.getUUID(identifier),
_id: id, // uuidMap.getUUID(identifier)
_source: source,
_label: label,
type: definition.type,
@@ -339,6 +361,7 @@ namespace TaskFilterDTO {
@extHostNamedCustomer(MainContext.MainThreadTask)
export class MainThreadTask implements MainThreadTaskShape {
private _extHostContext: IExtHostContext;
private _proxy: ExtHostTaskShape;
private _activeHandles: { [handle: number]: boolean; };
@@ -352,9 +375,13 @@ export class MainThreadTask implements MainThreadTaskShape {
this._taskService.onDidStateChange((event: TaskEvent) => {
let task = event.__task;
if (event.kind === TaskEventKind.Start) {
this._proxy.$taskStarted(TaskExecutionDTO.from(Task.getTaskExecution(task)));
this._proxy.$onDidStartTask(TaskExecutionDTO.from(Task.getTaskExecution(task)));
} else if (event.kind === TaskEventKind.ProcessStarted) {
this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(Task.getTaskExecution(task), event.processId));
} else if (event.kind === TaskEventKind.ProcessEnded) {
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(Task.getTaskExecution(task), event.exitCode));
} else if (event.kind === TaskEventKind.End) {
this._proxy.$taskEnded(TaskExecutionDTO.from(Task.getTaskExecution(task)));
this._proxy.$OnDidEndTask(TaskExecutionDTO.from(Task.getTaskExecution(task)));
}
});
}
@@ -368,17 +395,26 @@ export class MainThreadTask implements MainThreadTaskShape {
public $registerTaskProvider(handle: number): TPromise<void> {
this._taskService.registerTaskProvider(handle, {
provideTasks: () => {
return this._proxy.$provideTasks(handle).then((value) => {
provideTasks: (validTypes: IStringDictionary<boolean>) => {
return this._proxy.$provideTasks(handle, validTypes).then((value) => {
let tasks: Task[] = [];
for (let task of value.tasks) {
if (ContributedTask.is(task)) {
let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
if (uri) {
delete (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(uri));
let taskTransfer = task._source as any as ExtensionTaskSourceTransfer;
if (taskTransfer.__workspaceFolder !== void 0 && taskTransfer.__definition !== void 0) {
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(taskTransfer.__workspaceFolder));
delete taskTransfer.__workspaceFolder;
let taskIdentifier = TaskDefinition.createTaskIdentifier(taskTransfer.__definition, console);
delete taskTransfer.__definition;
if (taskIdentifier !== void 0) {
(task as ContributedTask).defines = taskIdentifier;
task._id = `${task._id}.${taskIdentifier._key}`;
tasks.push(task);
}
} else {
console.warn(`Dropping task ${task.name}. Missing workspace folder and task definition`);
}
}
value.tasks = tasks;
return value;
});
}
@@ -417,11 +453,11 @@ export class MainThreadTask implements MainThreadTaskShape {
task: TaskDTO.from(task)
};
resolve(result);
}, (error) => {
}, (_error) => {
reject(new Error('Task not found'));
});
} else {
let task = TaskDTO.to(value, this._workspaceContextServer);
let task = TaskDTO.to(value, this._workspaceContextServer, true);
this._taskService.run(task);
let result: TaskExecutionDTO = {
id: task._id,
@@ -449,4 +485,37 @@ export class MainThreadTask implements MainThreadTaskShape {
});
});
}
public $registerTaskSystem(key: string, info: TaskSystemInfoDTO): void {
let platform: Platform.Platform;
switch (info.platform) {
case 'win32':
platform = Platform.Platform.Windows;
break;
case 'darwin':
platform = Platform.Platform.Mac;
break;
case 'linux':
platform = Platform.Platform.Linux;
break;
default:
platform = Platform.platform;
}
this._taskService.registerTaskSystem(key, {
platform: platform,
uriProvider: (path: string): URI => {
return URI.parse(`${info.scheme}://${info.host}:${info.port}${path}`);
},
context: this._extHostContext,
resolveVariables: (workspaceFolder: IWorkspaceFolder, variables: Set<string>): TPromise<Map<string, string>> => {
let vars: string[] = [];
variables.forEach(item => vars.push(item));
return this._proxy.$resolveVariables(workspaceFolder.uri, vars).then(values => {
let result = new Map<string, string>();
Object.keys(values).forEach(key => result.set(key, values[key]));
return result;
});
}
});
}
}

View File

@@ -5,9 +5,9 @@
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/parts/terminal/common/terminal';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from '../node/extHost.protocol';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
@@ -16,28 +16,35 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
private _proxy: ExtHostTerminalServiceShape;
private _toDispose: IDisposable[] = [];
private _terminalProcesses: { [id: number]: ITerminalProcessExtHostProxy } = {};
private _dataListeners: { [id: number]: IDisposable } = {};
private _terminalOnDidWriteDataListeners: { [id: number]: IDisposable } = {};
private _terminalOnDidAcceptInputListeners: { [id: number]: IDisposable } = {};
constructor(
extHostContext: IExtHostContext,
@ITerminalService private terminalService: ITerminalService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._toDispose.push(terminalService.onInstanceCreated((terminalInstance) => {
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
// Delay this message so the TerminalInstance constructor has a chance to finish and
// return the ID normally to the extension host. The ID that is passed here will be used
// to register non-extension API terminals in the extension host.
setTimeout(() => this._onTerminalOpened(terminalInstance), 100);
setTimeout(() => this._onTerminalOpened(instance), EXT_HOST_CREATION_DELAY);
}));
this._toDispose.push(terminalService.onInstanceDisposed(terminalInstance => this._onTerminalDisposed(terminalInstance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady(terminalInstance => this._onTerminalProcessIdReady(terminalInstance)));
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : undefined)));
// Set initial ext host state
this.terminalService.terminalInstances.forEach(t => {
this._onTerminalOpened(t);
t.processReady.then(() => this._onTerminalProcessIdReady(t));
});
const activeInstance = this.terminalService.getActiveInstance();
if (activeInstance) {
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
}
}
public dispose(): void {
@@ -60,8 +67,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
return TPromise.as(this.terminalService.createTerminal(shellLaunchConfig).id);
}
public $createTerminalRenderer(name: string): TPromise<number> {
const instance = this.terminalService.createTerminalRenderer(name);
return TPromise.as(instance.id);
}
public $show(terminalId: number, preserveFocus: boolean): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
this.terminalService.setActiveInstance(terminalInstance);
this.terminalService.showPanel(!preserveFocus);
@@ -75,31 +87,86 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
public $dispose(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.dispose();
}
}
public $terminalRendererWrite(terminalId: number, text: string): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
terminalInstance.write(text);
}
}
public $terminalRendererSetName(terminalId: number, name: string): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
terminalInstance.setTitle(name, false);
}
}
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
terminalInstance.setDimensions(dimensions);
}
}
public $terminalRendererRegisterOnInputListener(terminalId: number): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (!terminalInstance) {
return;
}
// Listener already registered
if (this._terminalOnDidAcceptInputListeners.hasOwnProperty(terminalId)) {
return;
}
// Register
this._terminalOnDidAcceptInputListeners[terminalId] = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data));
terminalInstance.addDisposable(this._terminalOnDidAcceptInputListeners[terminalId]);
}
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.sendText(text, addNewLine);
}
}
public $registerOnDataListener(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
this._dataListeners[terminalId] = terminalInstance.onData(data => this._onTerminalData(terminalId, data));
terminalInstance.onDisposed(instance => delete this._dataListeners[terminalId]);
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (!terminalInstance) {
return;
}
// Listener already registered
if (this._terminalOnDidWriteDataListeners[terminalId]) {
return;
}
// Register
this._terminalOnDidWriteDataListeners[terminalId] = terminalInstance.onData(data => {
this._onTerminalData(terminalId, data);
});
terminalInstance.addDisposable(this._terminalOnDidWriteDataListeners[terminalId]);
}
private _onActiveTerminalChanged(terminalId: number | undefined): void {
this._proxy.$acceptActiveTerminalChanged(terminalId);
}
private _onTerminalData(terminalId: number, data: string): void {
this._proxy.$acceptTerminalProcessData(terminalId, data);
}
private _onTerminalRendererInput(terminalId: number, data: string): void {
this._proxy.$acceptTerminalRendererInput(terminalId, data);
}
private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
this._proxy.$acceptTerminalClosed(terminalInstance.id);
}
@@ -112,6 +179,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
}
private _onInstanceDimensionsChanged(instance: ITerminalInstance): void {
// Only send the dimensions if the terminal is a renderer only as there is no API to access
// dimensions on a plain Terminal.
if (instance.shellLaunchConfig.isRendererOnly) {
this._proxy.$acceptTerminalRendererDimensions(instance.id, instance.cols, instance.rows);
}
}
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
this._terminalProcesses[request.proxy.terminalId] = request.proxy;
const shellLaunchConfigDto: ShellLaunchConfigDto = {
@@ -123,7 +198,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
};
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.cols, request.rows);
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
request.proxy.onResize((cols, rows) => this._proxy.$acceptProcessResize(request.proxy.terminalId, cols, rows));
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
request.proxy.onShutdown(() => this._proxy.$acceptProcessShutdown(request.proxy.terminalId));
}

View File

@@ -4,11 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Event, Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer, ViewsRegistry, ICustomViewDescriptor } from 'vs/workbench/common/views';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -29,32 +28,55 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
$registerTreeViewDataProvider(treeViewId: string): void {
const dataProvider = this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService));
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
this._dataProviders.set(treeViewId, dataProvider);
const treeViewer = this.viewsService.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = dataProvider;
const viewer = this.getTreeViewer(treeViewId);
if (viewer) {
viewer.dataProvider = dataProvider;
this.registerListeners(treeViewId, viewer);
this._proxy.$setVisible(treeViewId, viewer.visible);
} else {
this.notificationService.error('No view is registered with id: ' + treeViewId);
}
}
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise<void> {
return this.viewsService.openView(treeViewId)
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): TPromise<void> {
return this.viewsService.openView(treeViewId, options.focus)
.then(() => {
const viewer = this.viewsService.getTreeViewer(treeViewId);
const viewer = this.getTreeViewer(treeViewId);
return viewer ? viewer.reveal(item, parentChain, options) : null;
});
}
$refresh(treeViewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): void {
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): TPromise<void> {
const viewer = this.getTreeViewer(treeViewId);
const dataProvider = this._dataProviders.get(treeViewId);
if (dataProvider) {
dataProvider.refresh(itemsToRefresh);
if (viewer && dataProvider) {
const itemsToRefresh = dataProvider.getItemsToRefresh(itemsToRefreshByHandle);
return viewer.refresh(itemsToRefresh.length ? itemsToRefresh : void 0);
}
return TPromise.as(null);
}
private registerListeners(treeViewId: string, treeViewer: ITreeViewer): void {
this._register(treeViewer.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
this._register(treeViewer.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
this._register(treeViewer.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
this._register(treeViewer.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)));
}
private getTreeViewer(treeViewId: string): ITreeViewer {
const viewDescriptor: ICustomViewDescriptor = <ICustomViewDescriptor>ViewsRegistry.getView(treeViewId);
return viewDescriptor ? viewDescriptor.treeViewer : null;
}
dispose(): void {
this._dataProviders.forEach((dataProvider, treeViewId) => {
const treeViewer = this.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = null;
}
});
this._dataProviders.clear();
super.dispose();
}
@@ -66,12 +88,6 @@ export type TreeItemHandle = string;
// {{SQL CARBON EDIT}}
export class TreeViewDataProvider implements ITreeViewDataProvider {
private readonly _onDidChange: Emitter<ITreeItem[] | undefined | null> = new Emitter<ITreeItem[] | undefined | null>();
readonly onDidChange: Event<ITreeItem[] | undefined | null> = this._onDidChange.event;
private readonly _onDispose: Emitter<void> = new Emitter<void>();
readonly onDispose: Event<void> = this._onDispose.event;
// {{SQL CARBON EDIT}}
protected itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
@@ -95,7 +111,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
});
}
refresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }) {
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): ITreeItem[] {
const itemsToRefresh: ITreeItem[] = [];
if (itemsToRefreshByHandle) {
for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
@@ -118,11 +134,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
}
}
}
if (itemsToRefresh.length) {
this._onDidChange.fire(itemsToRefresh);
} else {
this._onDidChange.fire();
}
return itemsToRefresh;
}
private postGetChildren(elements: ITreeItem[]): ITreeItem[] {
@@ -145,8 +157,4 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
}
}
}
dispose(): void {
this._onDispose.fire();
}
}

View File

@@ -42,7 +42,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
this.proxy = context.getProxy(ExtHostContext.ExtHostUrls);
}
$registerProtocolHandler(handle: number, extensionId: string): TPromise<void> {
$registerUriHandler(handle: number, extensionId: string): TPromise<void> {
const handler = new ExtensionUrlHandler(this.proxy, handle, extensionId);
const disposable = this.urlService.registerHandler(handler);
@@ -52,7 +52,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
return TPromise.as(null);
}
$unregisterProtocolHandler(handle: number): TPromise<void> {
$unregisterUriHandler(handle: number): TPromise<void> {
const tuple = this.handlers.get(handle);
if (!tuple) {

View File

@@ -2,29 +2,27 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import * as map from 'vs/base/common/map';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { localize } from 'vs/nls';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Position } from 'vs/platform/editor/common/editor';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/node/extHost.protocol';
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/shared/editor';
import { WebviewEditor } from 'vs/workbench/parts/webview/electron-browser/webviewEditor';
import { WebviewEditorInput } from 'vs/workbench/parts/webview/electron-browser/webviewEditorInput';
import { IWebviewEditorService, WebviewInputOptions, WebviewReviver } from 'vs/workbench/parts/webview/electron-browser/webviewEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions, WebviewReviver } from 'vs/workbench/parts/webview/electron-browser/webviewEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import * as vscode from 'vscode';
import { extHostNamedCustomer } from './extHostCustomers';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
private static readonly serializeTimeout = 500; // ms
private static readonly viewType = 'mainThreadWebview';
private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto'];
@@ -41,18 +39,17 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
constructor(
context: IExtHostContext,
@IContextKeyService contextKeyService: IContextKeyService,
@IEditorGroupService editorGroupService: IEditorGroupService,
@ILifecycleService lifecycleService: ILifecycleService,
@IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IEditorService private readonly _editorService: IEditorService,
@IWebviewEditorService private readonly _webviewService: IWebviewEditorService,
@IOpenerService private readonly _openerService: IOpenerService,
@IExtensionService private readonly _extensionService: IExtensionService,
) {
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
editorGroupService.onEditorsChanged(this.onEditorsChanged, this, this._toDispose);
editorGroupService.onEditorGroupMoved(this.onEditorGroupMoved, this, this._toDispose);
_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose);
_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose);
this._toDispose.push(_webviewService.registerReviver(MainThreadWebviews.viewType, this));
@@ -61,19 +58,25 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
}, this, this._toDispose);
}
dispose(): void {
public dispose(): void {
this._toDispose = dispose(this._toDispose);
}
$createWebviewPanel(
public $createWebviewPanel(
handle: WebviewPanelHandle,
viewType: string,
title: string,
column: Position,
showOptions: { viewColumn: EditorViewColumn | null, preserveFocus: boolean },
options: WebviewInputOptions,
extensionFolderPath: string
extensionLocation: UriComponents
): void {
const webview = this._webviewService.createWebview(MainThreadWebviews.viewType, title, column, options, extensionFolderPath, this.createWebviewEventDelegate(handle));
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
if (showOptions) {
mainThreadShowOptions.preserveFocus = showOptions.preserveFocus;
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
}
const webview = this._webviewService.createWebview(MainThreadWebviews.viewType, title, mainThreadShowOptions, reviveWebviewOptions(options), URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
webview.state = {
viewType: viewType,
state: undefined
@@ -83,33 +86,45 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._activeWebview = handle;
}
$disposeWebview(handle: WebviewPanelHandle): void {
public $disposeWebview(handle: WebviewPanelHandle): void {
const webview = this.getWebview(handle);
webview.dispose();
}
$setTitle(handle: WebviewPanelHandle, value: string): void {
public $setTitle(handle: WebviewPanelHandle, value: string): void {
const webview = this.getWebview(handle);
webview.setName(value);
}
$setHtml(handle: WebviewPanelHandle, value: string): void {
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
const webview = this.getWebview(handle);
webview.iconPath = reviveWebviewIcon(value);
}
public $setHtml(handle: WebviewPanelHandle, value: string): void {
const webview = this.getWebview(handle);
webview.html = value;
}
$reveal(handle: WebviewPanelHandle, column: Position | null): void {
public $setOptions(handle: WebviewPanelHandle, options: vscode.WebviewOptions): void {
const webview = this.getWebview(handle);
webview.setOptions(reviveWebviewOptions(options));
}
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
const webview = this.getWebview(handle);
if (webview.isDisposed()) {
return;
}
this._webviewService.revealWebview(webview, column);
const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn));
this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, showOptions.preserveFocus);
}
async $postMessage(handle: WebviewPanelHandle, message: any): TPromise<boolean> {
public $postMessage(handle: WebviewPanelHandle, message: any): TPromise<boolean> {
const webview = this.getWebview(handle);
const editors = this._editorService.getVisibleEditors()
const editors = this._editorService.visibleControls
.filter(e => e instanceof WebviewEditor)
.map(e => e as WebviewEditor)
.filter(e => e.input.matches(webview));
@@ -118,68 +133,56 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
editor.sendMessage(message);
}
return (editors.length > 0);
return TPromise.as(editors.length > 0);
}
$registerSerializer(viewType: string): void {
public $registerSerializer(viewType: string): void {
this._revivers.add(viewType);
}
$unregisterSerializer(viewType: string): void {
public $unregisterSerializer(viewType: string): void {
this._revivers.delete(viewType);
}
reviveWebview(webview: WebviewEditorInput): TPromise<void> {
public reviveWebview(webview: WebviewEditorInput): TPromise<void> {
const viewType = webview.state.viewType;
return this._extensionService.activateByEvent(`onView:${viewType}`).then(() => {
return this._extensionService.activateByEvent(`onWebviewPanel:${viewType}`).then(() => {
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
this._webviews.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
return this._proxy.$deserializeWebviewPanel(handle, webview.state.viewType, webview.getTitle(), webview.state.state, webview.position, webview.options)
let state = undefined;
if (webview.state.state) {
try {
state = JSON.parse(webview.state.state);
} catch {
// noop
}
}
return this._proxy.$deserializeWebviewPanel(handle, webview.state.viewType, webview.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webview.group), webview.options)
.then(undefined, () => {
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
});
});
}
canRevive(webview: WebviewEditorInput): boolean {
if (webview.isDisposed()) {
public canRevive(webview: WebviewEditorInput): boolean {
if (webview.isDisposed() || !webview.state) {
return false;
}
return this._revivers.has(webview.viewType) || webview.reviver !== null;
return this._revivers.has(webview.state.viewType) || !!webview.reviver;
}
private _onWillShutdown(): TPromise<boolean> {
const toRevive: WebviewPanelHandle[] = [];
this._webviews.forEach((view, key) => {
this._webviews.forEach((view) => {
if (this.canRevive(view)) {
toRevive.push(key);
view.state.state = view.webviewState;
}
});
const reviveResponses = toRevive.map(handle =>
TPromise.any([
this._proxy.$serializeWebviewPanel(handle).then(
state => ({ handle, state }),
() => ({ handle, state: null })),
TPromise.timeout(MainThreadWebviews.serializeTimeout).then(() => ({ handle, state: null }))
]).then(x => x.value));
return TPromise.join(reviveResponses).then(results => {
for (const result of results) {
const view = this._webviews.get(result.handle);
if (view) {
if (result.state) {
view.state.state = result.state;
} else {
view.state = null;
}
}
}
return false; // Don't veto shutdown
});
return TPromise.as(false); // Don't veto shutdown
}
private createWebviewEventDelegate(handle: WebviewPanelHandle) {
@@ -187,23 +190,18 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
onDidClickLink: uri => this.onDidClickLink(handle, uri),
onMessage: message => this._proxy.$onMessage(handle, message),
onDispose: () => {
const cleanUp = () => {
this._webviews.delete(handle);
};
this._proxy.$onDidDisposeWebviewPanel(handle).then(
() => this._webviews.delete(handle),
() => this._webviews.delete(handle));
cleanUp,
cleanUp);
}
};
}
private getWebview(handle: WebviewPanelHandle): WebviewEditorInput {
const webview = this._webviews.get(handle);
if (!webview) {
throw new Error('Unknown webview handle:' + handle);
}
return webview;
}
private onEditorsChanged() {
const activeEditor = this._editorService.getActiveEditor();
private onActiveEditorChanged() {
const activeEditor = this._editorService.activeControl;
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined;
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
for (const handle of map.keys(this._webviews)) {
@@ -217,7 +215,11 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
if (newActiveWebview && newActiveWebview.handle === this._activeWebview) {
// Webview itself unchanged but position may have changed
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, true, newActiveWebview.input.position);
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
active: true,
visible: true,
position: editorGroupToViewColumn(this._editorGroupService, newActiveWebview.input.group)
});
return;
}
@@ -225,33 +227,45 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
if (typeof this._activeWebview !== 'undefined') {
const oldActiveWebview = this._webviews.get(this._activeWebview);
if (oldActiveWebview) {
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, false, oldActiveWebview.position);
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, {
active: false,
visible: this._editorService.visibleControls.some(editor => editor.input && editor.input.matches(oldActiveWebview)),
position: editorGroupToViewColumn(this._editorGroupService, oldActiveWebview.group),
});
}
}
// Then for newly active
if (newActiveWebview) {
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, true, activeEditor.position);
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
active: true,
visible: true,
position: editorGroupToViewColumn(this._editorGroupService, activeEditor.group)
});
this._activeWebview = newActiveWebview.handle;
} else {
this._activeWebview = undefined;
}
}
private onEditorGroupMoved(): void {
for (const workbenchEditor of this._editorService.getVisibleEditors()) {
if (!workbenchEditor.input) {
return;
}
private onVisibleEditorsChanged(): void {
this._webviews.forEach((input, handle) => {
for (const workbenchEditor of this._editorService.visibleControls) {
if (workbenchEditor.input && workbenchEditor.input.matches(input)) {
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
this._webviews.forEach((input, handle) => {
if (workbenchEditor.input.matches(input) && input.position !== workbenchEditor.position) {
input.updatePosition(workbenchEditor.position);
this._proxy.$onDidChangeWebviewPanelViewState(handle, handle === this._activeWebview, workbenchEditor.position);
input.updateGroup(workbenchEditor.group.id);
this._proxy.$onDidChangeWebviewPanelViewState(handle, {
active: handle === this._activeWebview,
visible: true,
position: editorPosition
});
break;
}
});
}
}
});
}
private onDidClickLink(handle: WebviewPanelHandle, link: URI): void {
if (!link) {
return;
@@ -264,6 +278,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
}
}
private getWebview(handle: WebviewPanelHandle): WebviewEditorInput {
const webview = this._webviews.get(handle);
if (!webview) {
throw new Error('Unknown webview handle:' + handle);
}
return webview;
}
private static getDeserializationFailedContents(viewType: string) {
return `<!DOCTYPE html>
<html>
@@ -276,3 +298,23 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
</html>`;
}
}
function reviveWebviewOptions(options: WebviewInputOptions): WebviewInputOptions {
return {
...options,
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(URI.revive) : undefined
};
}
function reviveWebviewIcon(
value: { light: UriComponents, dark: UriComponents } | undefined
): { light: URI, dark: URI } | undefined {
if (!value) {
return undefined;
}
return {
light: URI.revive(value.light),
dark: URI.revive(value.dark)
};
}

View File

@@ -5,18 +5,24 @@
'use strict';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import URI, { UriComponents } from 'vs/base/common/uri';
import { ISearchService, QueryType, ISearchQuery, IFolderQuery, ISearchConfiguration } from 'vs/platform/search/common/search';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IFileMatch, IFolderQuery, IPatternInfo, IQueryOptions, ISearchConfiguration, ISearchQuery, ISearchService, QueryType, ISearchProgressItem } from 'vs/platform/search/common/search';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { QueryBuilder } from 'vs/workbench/parts/search/common/queryBuilder';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWindowService } from 'vs/platform/windows/common/windows';
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@@ -32,7 +38,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@ITextFileService private readonly _textFileService: ITextFileService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
@IStatusbarService private readonly _statusbarService: IStatusbarService
@IStatusbarService private readonly _statusbarService: IStatusbarService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
@@ -97,7 +104,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
// --- search ---
$startSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<URI[]> {
$startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<URI[]> {
const workspace = this._contextService.getWorkspace();
if (!workspace.folders.length) {
return undefined;
@@ -128,12 +135,18 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
folderQueries,
type: QueryType.File,
maxResults,
includePattern: { [typeof includePattern === 'string' ? includePattern : undefined]: true },
excludePattern: { [typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined]: true },
disregardExcludeSettings: excludePatternOrDisregardExcludes === false,
useRipgrep,
ignoreSymlinks
};
if (typeof includePattern === 'string') {
query.includePattern = { [includePattern]: true };
}
if (typeof excludePatternOrDisregardExcludes === 'string') {
query.excludePattern = { [excludePatternOrDisregardExcludes]: true };
}
this._searchService.extendQuery(query);
const search = this._searchService.search(query).then(result => {
@@ -152,6 +165,38 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
return search;
}
$startTextSearch(pattern: IPatternInfo, options: IQueryOptions, requestId: number): TPromise<void, IFileMatch> {
const workspace = this._contextService.getWorkspace();
const folders = workspace.folders.map(folder => folder.uri);
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.text(pattern, folders, options);
const onProgress = (p: ISearchProgressItem) => {
if (p.lineMatches) {
this._proxy.$handleTextSearchResult(p, requestId);
}
};
const search = this._searchService.search(query, onProgress).then(
() => {
delete this._activeSearches[requestId];
return null;
},
err => {
delete this._activeSearches[requestId];
if (!isPromiseCanceledError(err)) {
return TPromise.wrapError(err);
}
return undefined;
});
this._activeSearches[requestId] = search;
return search;
}
$cancelSearch(requestId: number): Thenable<boolean> {
const search = this._activeSearches[requestId];
if (search) {
@@ -170,3 +215,19 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
});
}
}
CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (accessor: ServicesAccessor, workspace: URI, disableExtensions: string[]) {
const workspaceEditingService = accessor.get(IWorkspaceEditingService);
const extensionService = accessor.get(IExtensionService);
const windowService = accessor.get(IWindowService);
if (disableExtensions && disableExtensions.length) {
const runningExtensions = await extensionService.getExtensions();
// If requested extension to disable is running, then reload window with given workspace
if (disableExtensions && runningExtensions.some(runningExtension => disableExtensions.some(id => areSameExtensions({ id }, { id: runningExtension.id })))) {
return windowService.openWindow([URI.file(workspace.fsPath)], { args: { _: [], 'disable-extension': disableExtensions } });
}
}
return workspaceEditingService.enterWorkspace(workspace.fsPath);
});