Cannot read property 'pushStackElement' of null (fix #93216)

This commit is contained in:
Benjamin Pasero 2020-03-27 14:33:41 +01:00
parent 537a2e783a
commit e68ccf21bf
5 changed files with 47 additions and 24 deletions

View file

@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ITextFileSaveParticipant, IResolvedTextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileSaveParticipant, ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
import { canceled } from 'vs/base/common/errors';
@ -23,9 +23,9 @@ class ExtHostSaveParticipant implements ITextFileSaveParticipant {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
}
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
if (!shouldSynchronizeModel(editorModel.textEditorModel)) {
if (!editorModel.textEditorModel || !shouldSynchronizeModel(editorModel.textEditorModel)) {
// the model never made it to the extension
// host meaning we cannot participate in its save
return undefined;

View file

@ -23,7 +23,7 @@ import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressStep, IProgress, Progress } from 'vs/platform/progress/common/progress';
import { IResolvedTextFileEditorModel, ITextFileService, ITextFileSaveParticipant } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileService, ITextFileSaveParticipant, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution, Extensions as WorkbenchContributionsExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
@ -39,7 +39,11 @@ export class TrimWhitespaceParticipant implements ITextFileSaveParticipant {
// Nothing
}
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
async participate(model: ITextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
if (!model.textEditorModel) {
return;
}
if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO);
}
@ -101,7 +105,11 @@ export class FinalNewLineParticipant implements ITextFileSaveParticipant {
// Nothing
}
async participate(model: IResolvedTextFileEditorModel, _env: { reason: SaveReason; }): Promise<void> {
async participate(model: ITextFileEditorModel, _env: { reason: SaveReason; }): Promise<void> {
if (!model.textEditorModel) {
return;
}
if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
this.doInsertFinalNewLine(model.textEditorModel);
}
@ -135,7 +143,11 @@ export class TrimFinalNewLinesParticipant implements ITextFileSaveParticipant {
// Nothing
}
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
async participate(model: ITextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
if (!model.textEditorModel) {
return;
}
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO);
}
@ -205,9 +217,13 @@ class FormatOnSaveParticipant implements ITextFileSaveParticipant {
// Nothing
}
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
const model = editorModel.textEditorModel;
const overrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri };
async participate(model: ITextFileEditorModel, env: { reason: SaveReason; }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
if (!model.textEditorModel) {
return;
}
const textEditorModel = model.textEditorModel;
const overrides = { overrideIdentifier: textEditorModel.getLanguageIdentifier().language, resource: textEditorModel.uri };
if (env.reason === SaveReason.AUTO || !this.configurationService.getValue('editor.formatOnSave', overrides)) {
return undefined;
@ -222,7 +238,7 @@ class FormatOnSaveParticipant implements ITextFileSaveParticipant {
)
});
});
const editorOrModel = findEditor(model, this.codeEditorService) || model;
const editorOrModel = findEditor(textEditorModel, this.codeEditorService) || textEditorModel;
await this.instantiationService.invokeFunction(formatDocumentWithSelectedProvider, editorOrModel, FormattingMode.Silent, nestedProgress, token);
}
}
@ -234,13 +250,17 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
@IInstantiationService private readonly instantiationService: IInstantiationService,
) { }
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
async participate(model: ITextFileEditorModel, env: { reason: SaveReason; }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
if (!model.textEditorModel) {
return;
}
if (env.reason === SaveReason.AUTO) {
return undefined;
}
const model = editorModel.textEditorModel;
const textEditorModel = model.textEditorModel;
const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.resource };
const settingsOverrides = { overrideIdentifier: textEditorModel.getLanguageIdentifier().language, resource: model.resource };
const setting = this.configurationService.getValue<{ [kind: string]: boolean } | string[]>('editor.codeActionsOnSave', settingsOverrides);
if (!setting) {
return undefined;
@ -279,7 +299,7 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
.map(x => new CodeActionKind(x));
progress.report({ message: localize('codeaction', "Quick Fixes") });
await this.applyOnSaveActions(model, codeActionsOnSave, excludedActions, progress, token);
await this.applyOnSaveActions(textEditorModel, codeActionsOnSave, excludedActions, progress, token);
}
private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: readonly CodeActionKind[], excludes: readonly CodeActionKind[], progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {

View file

@ -9,7 +9,7 @@ import { Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ITextFileEditorModel, ITextFileEditorModelManager, ITextFileEditorModelLoadOrCreateOptions, ITextFileLoadEvent, ITextFileSaveEvent, ITextFileSaveParticipant, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileEditorModel, ITextFileEditorModelManager, ITextFileEditorModelLoadOrCreateOptions, ITextFileLoadEvent, ITextFileSaveEvent, ITextFileSaveParticipant } from 'vs/workbench/services/textfile/common/textfiles';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ResourceMap } from 'vs/base/common/map';
@ -388,7 +388,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
return this.saveParticipants.addSaveParticipant(participant);
}
runSaveParticipants(model: IResolvedTextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> {
runSaveParticipants(model: ITextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> {
return this.saveParticipants.participate(model, context, token);
}

View file

@ -8,7 +8,7 @@ import { raceCancellation } from 'vs/base/common/async';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { ITextFileSaveParticipant, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextFileSaveParticipant, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
@ -29,7 +29,7 @@ export class TextFileSaveParticipant extends Disposable {
return toDisposable(() => this.saveParticipants.splice(this.saveParticipants.indexOf(participant), 1));
}
participate(model: IResolvedTextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> {
participate(model: ITextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> {
const cts = new CancellationTokenSource(token);
return this.progressService.withProgress({
@ -40,10 +40,10 @@ export class TextFileSaveParticipant extends Disposable {
}, async progress => {
// undoStop before participation
model.textEditorModel.pushStackElement();
model.textEditorModel?.pushStackElement();
for (const saveParticipant of this.saveParticipants) {
if (cts.token.isCancellationRequested) {
if (cts.token.isCancellationRequested || !model.textEditorModel /* disposed */) {
break;
}
@ -56,7 +56,7 @@ export class TextFileSaveParticipant extends Disposable {
}
// undoStop after participation
model.textEditorModel.pushStackElement();
model.textEditorModel?.pushStackElement();
}, () => {
// user cancel
cts.dispose(true);

View file

@ -310,7 +310,7 @@ export interface ITextFileSaveParticipant {
* before it is being saved to disk.
*/
participate(
model: IResolvedTextFileEditorModel,
model: ITextFileEditorModel,
context: { reason: SaveReason },
progress: IProgress<IProgressStep>,
token: CancellationToken
@ -347,7 +347,10 @@ export interface ITextFileEditorModelManager {
*/
addSaveParticipant(participant: ITextFileSaveParticipant): IDisposable;
runSaveParticipants(model: IResolvedTextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void>
/**
* Runs the registered save participants on the provided model.
*/
runSaveParticipants(model: ITextFileEditorModel, context: { reason: SaveReason; }, token: CancellationToken): Promise<void>
disposeModel(model: ITextFileEditorModel): void;
}