提交 228978ab 编写于 作者: M Matt Bierner

Strict null work in mainThreadSave

上级 1cd1f811
......@@ -7,7 +7,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IdleValue, sequence } from 'vs/base/common/async';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import * as strings from 'vs/base/common/strings';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
......@@ -60,7 +60,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
let prevSelection: Selection[] = [];
let cursors: Position[] = [];
let editor = findEditor(model, this.codeEditorService);
const editor = findEditor(model, this.codeEditorService);
if (editor) {
// Find `prevSelection` in any case do ensure a good undo stack when pushing the edit
// Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump
......@@ -85,12 +85,12 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
}
}
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): ICodeEditor {
let candidate: ICodeEditor | null = null;
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): IActiveCodeEditor | null {
let candidate: IActiveCodeEditor | null = null;
if (model.isAttachedToEditor()) {
for (const editor of codeEditorService.listCodeEditors()) {
if (editor.getModel() === model) {
if (editor.hasModel() && editor.getModel() === model) {
if (editor.hasTextFocus()) {
return editor; // favour focused editor if there are multiple
}
......@@ -233,7 +233,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
return new Promise<ISingleEditOperation[]>((resolve, reject) => {
return new Promise<ISingleEditOperation[] | null | undefined>((resolve, reject) => {
let source = new CancellationTokenSource();
let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces }, source.token);
......@@ -277,7 +277,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return undefined;
return null;
});
}
......@@ -425,7 +425,7 @@ export class SaveParticipant implements ISaveParticipant {
}
dispose(): void {
TextFileEditorModel.setSaveParticipant(undefined);
TextFileEditorModel.setSaveParticipant(null);
this._saveParticipants.dispose();
}
......
......@@ -638,7 +638,7 @@ export class EditorModel extends Disposable implements IEditorModel {
/**
* Causes this model to load returning a promise when loading is completed.
*/
load(): Promise<EditorModel> {
load(): Promise<IEditorModel> {
return Promise.resolve(this);
}
......
......@@ -45,8 +45,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private static saveErrorHandler: ISaveErrorHandler;
static setSaveErrorHandler(handler: ISaveErrorHandler): void { TextFileEditorModel.saveErrorHandler = handler; }
private static saveParticipant: ISaveParticipant;
static setSaveParticipant(handler: ISaveParticipant): void { TextFileEditorModel.saveParticipant = handler; }
private static saveParticipant: ISaveParticipant | null;
static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; }
private readonly _onDidContentChange: Emitter<StateChange> = this._register(new Emitter<StateChange>());
get onDidContentChange(): Event<StateChange> { return this._onDidContentChange.event; }
......@@ -62,9 +62,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private bufferSavedVersionId: number;
private lastResolvedDiskStat: IFileStat;
private blockModelContentChange: boolean;
private autoSaveAfterMillies: number;
private autoSaveAfterMillies?: number;
private autoSaveAfterMilliesEnabled: boolean;
private autoSaveDisposable: IDisposable;
private autoSaveDisposable?: IDisposable;
private contentChangeEventScheduler: RunOnceScheduler;
private orphanedChangeEventScheduler: RunOnceScheduler;
private saveSequentializer: SaveSequentializer;
......@@ -129,7 +129,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private onFileChanges(e: FileChangesEvent): void {
let fileEventImpactsModel = false;
let newInOrphanModeGuess: boolean;
let newInOrphanModeGuess: boolean | undefined;
// If we are currently orphaned, we check if the model file was added back
if (this.inOrphanMode) {
......@@ -235,7 +235,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
});
}
load(options?: ILoadOptions): Promise<TextFileEditorModel> {
load(options?: ILoadOptions): Promise<ITextFileEditorModel> {
this.logService.trace('load() - enter', this.resource);
// It is very important to not reload the model when the model is dirty.
......@@ -289,7 +289,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
const allowBinary = this.isResolved() /* always allow if we resolved previously */ || (options && options.allowBinary);
// Decide on etag
let etag: string;
let etag: string | undefined;
if (forceReadFromDisk) {
etag = undefined; // reset ETag if we enforce to read from disk
} else if (this.lastResolvedDiskStat) {
......@@ -491,7 +491,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
return this.backupFileService.resolveBackupContent(backup).then(backupContent => backupContent, error => null /* ignore errors */);
}
protected getOrCreateMode(modeService: IModeService, preferredModeIds: string, firstLineText?: string): ILanguageSelection {
protected getOrCreateMode(modeService: IModeService, preferredModeIds: string | undefined, firstLineText?: string): ILanguageSelection {
return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText);
}
......@@ -914,7 +914,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
return this.lastSaveAttemptTime;
}
getETag(): string {
getETag(): string | null {
return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag : null;
}
......@@ -1046,8 +1046,8 @@ interface ISaveOperation {
}
export class SaveSequentializer {
private _pendingSave: IPendingSave;
private _nextSave: ISaveOperation;
private _pendingSave?: IPendingSave;
private _nextSave?: ISaveOperation;
hasPendingSave(versionId?: number): boolean {
if (!this._pendingSave) {
......@@ -1061,7 +1061,7 @@ export class SaveSequentializer {
return !!this._pendingSave;
}
get pendingSave(): Promise<void> {
get pendingSave(): Promise<void> | undefined {
return this._pendingSave ? this._pendingSave.promise : undefined;
}
......
......@@ -236,7 +236,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport
hasState(state: ModelState): boolean;
getETag(): string;
getETag(): string | null;
updatePreferredEncoding(encoding: string): void;
......@@ -246,7 +246,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport
revert(soft?: boolean): Promise<void>;
createSnapshot(): ITextSnapshot;
createSnapshot(): ITextSnapshot | null;
isDirty(): boolean;
......
......@@ -43,31 +43,31 @@ suite('MainThreadSaveParticipant', function () {
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'insertFinalNewline': true });
const participant = new FinalNewLineParticipant(configService, undefined);
const participant = new FinalNewLineParticipant(configService, undefined!);
// No new line for empty lines
let lineContent = '';
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// No new line if last line already empty
lineContent = `Hello New Line${model.textEditorModel.getEOL()}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// New empty line added (single line)
lineContent = 'Hello New Line';
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`);
// New empty line added (multi line)
lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`);
});
test('trim final new lines', async function () {
......@@ -76,7 +76,7 @@ suite('MainThreadSaveParticipant', function () {
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Trim New Line';
const eol = `${model.textEditorModel.getEOL()}`;
......@@ -84,25 +84,25 @@ suite('MainThreadSaveParticipant', function () {
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// No new line removal if last line is single new line
lineContent = `${textContent}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// Remove new line (single line with two new lines)
lineContent = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
// Remove new lines (multiple lines with multiple new lines)
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${textContent}${eol}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${textContent}${eol}`);
});
test('trim final new lines bug#39750', async function () {
......@@ -111,7 +111,7 @@ suite('MainThreadSaveParticipant', function () {
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Trim New Line';
// single line
......@@ -124,12 +124,12 @@ suite('MainThreadSaveParticipant', function () {
// undo
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}`);
// trim final new lines should not mess the undo stack
await participant.participate(model, { reason: SaveReason.EXPLICIT });
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}.`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}.`);
});
test('trim final new lines bug#46075', async function () {
......@@ -138,7 +138,7 @@ suite('MainThreadSaveParticipant', function () {
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Test';
const eol = `${model.textEditorModel.getEOL()}`;
let content = `${textContent}${eol}${eol}`;
......@@ -150,12 +150,12 @@ suite('MainThreadSaveParticipant', function () {
}
// confirm trimming
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
// undo should go back to previous content immediately
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${eol}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${eol}`);
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册