Have workspace.applyEdit correctly account for model version changes and reply with false if a model was loaded and changed in the meantime

This commit is contained in:
Alex Dima
2017-09-18 16:55:47 +02:00
parent 012d7da5bc
commit 02ee356269
13 changed files with 333 additions and 99 deletions

View File

@@ -84,7 +84,7 @@ export function createApiFactory(
const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService, extensionService));
const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors));
const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors));
const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace)));
const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadEditors)));
const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService));
const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands));
@@ -417,7 +417,7 @@ export function createApiFactory(
return extHostWorkspace.saveAll(includeUntitled);
},
applyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
return extHostWorkspace.appyEdit(edit);
return extHostEditors.applyWorkspaceEdit(edit);
},
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
return extHostFileSystemEvent.createFileSystemWatcher(pattern, ignoreCreate, ignoreChange, ignoreDelete);

View File

@@ -26,7 +26,6 @@ import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/pro
import * as editorCommon from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { ITextSource } from 'vs/editor/common/model/textSource';
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
@@ -189,6 +188,16 @@ export interface ITextDocumentShowOptions {
selection?: IRange;
}
export interface IWorkspaceResourceEdit {
resource: URI;
modelVersionId?: number;
edits: {
range?: IRange;
newText: string;
newEol?: editorCommon.EndOfLineSequence;
}[];
}
export interface MainThreadEditorsShape extends IDisposable {
$tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise<string>;
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
@@ -200,6 +209,7 @@ export interface MainThreadEditorsShape extends IDisposable {
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any>;
$trySetSelections(id: string, selections: ISelection[]): TPromise<any>;
$tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean>;
$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean>;
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise<any>;
$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]>;
}
@@ -301,7 +311,6 @@ export interface MainThreadWorkspaceShape extends IDisposable {
$startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable<URI[]>;
$cancelSearch(requestId: number): Thenable<boolean>;
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
$applyWorkspaceEdit(edits: IResourceEdit[]): TPromise<boolean>;
$registerFileSystemProvider(handle: number, authority: string): void;
$unregisterFileSystemProvider(handle: number): void;

View File

@@ -10,10 +10,9 @@ import URI from 'vs/base/common/uri';
import { sequence, always } from 'vs/base/common/async';
import { illegalState } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainThreadWorkspaceShape, ExtHostDocumentSaveParticipantShape } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol';
import { TextEdit } from 'vs/workbench/api/node/extHostTypes';
import { fromRange, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import * as vscode from 'vscode';
@@ -21,14 +20,14 @@ import * as vscode from 'vscode';
export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSaveParticipantShape {
private _documents: ExtHostDocuments;
private _workspace: MainThreadWorkspaceShape;
private _mainThreadEditors: MainThreadEditorsShape;
private _callbacks = new CallbackList();
private _badListeners = new WeakMap<Function, number>();
private _thresholds: { timeout: number; errors: number; };
constructor(documents: ExtHostDocuments, workspace: MainThreadWorkspaceShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) {
constructor(documents: ExtHostDocuments, mainThreadEditors: MainThreadEditorsShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) {
this._documents = documents;
this._workspace = workspace;
this._mainThreadEditors = mainThreadEditors;
this._thresholds = thresholds;
}
@@ -133,13 +132,15 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}).then(values => {
let edits: IResourceEdit[] = [];
let workspaceResourceEdit: IWorkspaceResourceEdit = {
resource: <URI>document.uri,
edits: []
};
for (const value of values) {
if (Array.isArray(value) && (<vscode.TextEdit[]>value).every(e => e instanceof TextEdit)) {
for (const { newText, newEol, range } of value) {
edits.push({
resource: <URI>document.uri,
workspaceResourceEdit.edits.push({
range: range && fromRange(range),
newText,
newEol: EndOfLine.from(newEol)
@@ -150,12 +151,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
// apply edits if any and if document
// didn't change somehow in the meantime
if (edits.length === 0) {
if (workspaceResourceEdit.edits.length === 0) {
return undefined;
}
if (version === document.version) {
return this._workspace.$applyWorkspaceEdit(edits);
return this._mainThreadEditors.$tryApplyWorkspaceEdit([workspaceResourceEdit]);
}
// TODO@joh bubble this to listener?

View File

@@ -13,7 +13,7 @@ import * as TypeConverters from './extHostTypeConverters';
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext } from './extHost.protocol';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, IWorkspaceResourceEdit } from './extHost.protocol';
import * as vscode from 'vscode';
export class ExtHostEditors implements ExtHostEditorsShape {
@@ -91,6 +91,40 @@ export class ExtHostEditors implements ExtHostEditorsShape {
return new TextEditorDecorationType(this._proxy, options);
}
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
let workspaceResourceEdits: IWorkspaceResourceEdit[] = [];
let entries = edit.entries();
for (let entry of entries) {
let [uri, edits] = entry;
let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString());
let docVersion: number = undefined;
if (doc) {
docVersion = doc.version;
}
let workspaceResourceEdit: IWorkspaceResourceEdit = {
resource: <URI>uri,
modelVersionId: docVersion,
edits: []
};
for (let edit of edits) {
workspaceResourceEdit.edits.push({
newText: edit.newText,
newEol: TypeConverters.EndOfLine.from(edit.newEol),
range: edit.range && TypeConverters.fromRange(edit.range)
});
}
workspaceResourceEdits.push(workspaceResourceEdit);
}
return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits);
}
// --- called from main thread
$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void {

View File

@@ -10,9 +10,7 @@ import { normalize } from 'vs/base/common/paths';
import { delta } from 'vs/base/common/arrays';
import { relative } from 'path';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { TPromise } from 'vs/base/common/winjs.base';
import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol';
import * as vscode from 'vscode';
import { compare } from 'vs/base/common/strings';
@@ -182,27 +180,6 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
return this._proxy.$saveAll(includeUntitled);
}
appyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
let resourceEdits: IResourceEdit[] = [];
let entries = edit.entries();
for (let entry of entries) {
let [uri, edits] = entry;
for (let edit of edits) {
resourceEdits.push({
resource: <URI>uri,
newText: edit.newText,
newEol: EndOfLine.from(edit.newEol),
range: edit.range && fromRange(edit.range)
});
}
}
return this._proxy.$applyWorkspaceEdit(resourceEdits);
}
// --- EXPERIMENT: workspace resolver