Merge from vscode 011858832762aaff245b2336fb1c38166e7a10fb (#4663)

This commit is contained in:
Anthony Dresser
2019-03-22 13:07:54 -07:00
committed by GitHub
parent f5c9174c2f
commit 4a87a24235
296 changed files with 2531 additions and 2472 deletions

View File

@@ -163,7 +163,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
const lineContent = model.getLineContent(lineNumber);
const indent = TextModel.computeIndentLevel(lineContent, tabSize);
const lineHasSpace = config.fontInfo.spaceWidth * indent > 22;
const isFolded = (lineNumber) => {
const isFolded = (lineNumber: number) => {
return lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1);
};

View File

@@ -25,7 +25,7 @@ class CodeLensViewZone implements editorBrowser.IViewZone {
afterLineNumber: number;
private _lastHeight: number;
private _lastHeight?: number;
private readonly _onHeight: Function;
constructor(afterLineNumber: number, onHeight: Function) {

View File

@@ -67,7 +67,7 @@ suite('FindController', () => {
getBoolean: (key: string) => !!queryState[key],
getNumber: (key: string) => undefined,
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
remove: (key) => undefined
remove: () => undefined
} as any);
if (platform.isMacintosh) {
@@ -442,7 +442,7 @@ suite('FindController query options persistence', () => {
getBoolean: (key: string) => !!queryState[key],
getNumber: (key: string) => undefined,
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
remove: (key) => undefined
remove: () => undefined
} as any);
test('matchCase', () => {

View File

@@ -66,7 +66,7 @@ export class FoldingModel {
public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {
let newEditorDecorations: IModelDeltaDecoration[] = [];
let isBlocked = (startLineNumber, endLineNumber) => {
let isBlocked = (startLineNumber: number, endLineNumber: number) => {
for (let blockedLineNumber of blockedLineNumers) {
if (startLineNumber < blockedLineNumber && blockedLineNumber <= endLineNumber) { // first line is visible
return true;

View File

@@ -3,138 +3,258 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { alert } from 'vs/base/browser/ui/aria/aria';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation';
import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { DocumentFormattingEditProviderRegistry, DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry, FormattingOptions, TextEdit } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { first } from 'vs/base/common/async';
import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState';
import { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerLanguageCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { Position } from 'vs/editor/common/core/position';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ISingleEditOperation, ITextModel } from 'vs/editor/common/model';
import { DocumentFormattingEditProvider, DocumentFormattingEditProviderRegistry, DocumentRangeFormattingEditProvider, DocumentRangeFormattingEditProviderRegistry, FormattingOptions, OnTypeFormattingEditProviderRegistry, TextEdit } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IModelService } from 'vs/editor/common/services/modelService';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import * as nls from 'vs/nls';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IDisposable } from 'vs/base/common/lifecycle';
export const enum FormatMode {
Auto = 1,
Manual = 2,
}
export function alertFormattingEdits(edits: ISingleEditOperation[]): void {
export const enum FormatKind {
Document = 8,
Range = 16,
OnType = 32,
}
edits = edits.filter(edit => edit.range);
if (!edits.length) {
return;
}
export interface IFormatterConflictCallback {
(extensionIds: (ExtensionIdentifier | undefined)[], model: ITextModel, mode: number): void;
}
let _conflictResolver: IFormatterConflictCallback | undefined;
export function setFormatterConflictCallback(callback: IFormatterConflictCallback): IDisposable {
let oldCallback = _conflictResolver;
_conflictResolver = callback;
return {
dispose() {
if (oldCallback) {
_conflictResolver = oldCallback;
oldCallback = undefined;
}
let { range } = edits[0];
for (let i = 1; i < edits.length; i++) {
range = Range.plusRange(range, edits[i].range);
}
const { startLineNumber, endLineNumber } = range;
if (startLineNumber === endLineNumber) {
if (edits.length === 1) {
alert(nls.localize('hint11', "Made 1 formatting edit on line {0}", startLineNumber));
} else {
alert(nls.localize('hintn1', "Made {0} formatting edits on line {1}", edits.length, startLineNumber));
}
} else {
if (edits.length === 1) {
alert(nls.localize('hint1n', "Made 1 formatting edit between lines {0} and {1}", startLineNumber, endLineNumber));
} else {
alert(nls.localize('hintnn', "Made {0} formatting edits between lines {1} and {2}", edits.length, startLineNumber, endLineNumber));
}
};
}
function invokeFormatterCallback<T extends { extensionId?: ExtensionIdentifier }>(formatter: T[], model: ITextModel, mode: number): void {
if (_conflictResolver) {
const ids = formatter.map(formatter => formatter.extensionId);
_conflictResolver(ids, model, mode);
}
}
export async function getDocumentRangeFormattingEdits(
telemetryService: ITelemetryService,
export function getRealAndSyntheticDocumentFormattersOrdered(model: ITextModel): DocumentFormattingEditProvider[] {
const result: DocumentFormattingEditProvider[] = [];
const seen = new Set<string>();
// (1) add all document formatter
const docFormatter = DocumentFormattingEditProviderRegistry.ordered(model);
for (const formatter of docFormatter) {
result.push(formatter);
if (formatter.extensionId) {
seen.add(ExtensionIdentifier.toKey(formatter.extensionId));
}
}
// (2) add all range formatter as document formatter (unless the same extension already did that)
const rangeFormatter = DocumentRangeFormattingEditProviderRegistry.ordered(model);
for (const formatter of rangeFormatter) {
if (formatter.extensionId) {
if (seen.has(ExtensionIdentifier.toKey(formatter.extensionId))) {
continue;
}
seen.add(ExtensionIdentifier.toKey(formatter.extensionId));
}
result.push({
displayName: formatter.displayName,
extensionId: formatter.extensionId,
provideDocumentFormattingEdits(model, options, token) {
return formatter.provideDocumentRangeFormattingEdits(model, model.getFullModelRange(), options, token);
}
});
}
return result;
}
export async function formatDocumentRangeWithProvider(
accessor: ServicesAccessor,
provider: DocumentRangeFormattingEditProvider,
editorOrModel: ITextModel | IActiveCodeEditor,
range: Range,
token: CancellationToken
): Promise<boolean> {
const workerService = accessor.get(IEditorWorkerService);
let model: ITextModel;
let validate: () => boolean;
if (isCodeEditor(editorOrModel)) {
model = editorOrModel.getModel();
const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
validate = () => state.validate(editorOrModel);
} else {
model = editorOrModel;
const versionNow = editorOrModel.getVersionId();
validate = () => versionNow === editorOrModel.getVersionId();
}
const rawEdits = await provider.provideDocumentRangeFormattingEdits(
model,
range,
model.getFormattingOptions(),
token
);
const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
if (!validate()) {
return true;
}
if (!edits || edits.length === 0) {
return false;
}
if (isCodeEditor(editorOrModel)) {
// use editor to apply edits
FormattingEdit.execute(editorOrModel, edits);
alertFormattingEdits(edits);
editorOrModel.pushUndoStop();
editorOrModel.focus();
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
} else {
// use model to apply edits
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
model.pushEditOperations([initialSelection], edits.map(edit => {
return {
text: edit.text,
range: Range.lift(edit.range),
forceMoveMarkers: true
};
}), undoEdits => {
for (const { range } of undoEdits) {
if (Range.areIntersectingOrTouching(range, initialSelection)) {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return null;
});
}
return true;
}
export async function formatDocumentWithProvider(
accessor: ServicesAccessor,
provider: DocumentFormattingEditProvider,
editorOrModel: ITextModel | IActiveCodeEditor,
token: CancellationToken
): Promise<boolean> {
const workerService = accessor.get(IEditorWorkerService);
let model: ITextModel;
let validate: () => boolean;
if (isCodeEditor(editorOrModel)) {
model = editorOrModel.getModel();
const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
validate = () => state.validate(editorOrModel);
} else {
model = editorOrModel;
const versionNow = editorOrModel.getVersionId();
validate = () => versionNow === editorOrModel.getVersionId();
}
const rawEdits = await provider.provideDocumentFormattingEdits(
model,
model.getFormattingOptions(),
token
);
const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
if (!validate()) {
return true;
}
if (!edits || edits.length === 0) {
return false;
}
if (isCodeEditor(editorOrModel)) {
// use editor to apply edits
FormattingEdit.execute(editorOrModel, edits);
alertFormattingEdits(edits);
editorOrModel.pushUndoStop();
editorOrModel.focus();
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
} else {
// use model to apply edits
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
model.pushEditOperations([initialSelection], edits.map(edit => {
return {
text: edit.text,
range: Range.lift(edit.range),
forceMoveMarkers: true
};
}), undoEdits => {
for (const { range } of undoEdits) {
if (Range.areIntersectingOrTouching(range, initialSelection)) {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return null;
});
}
return true;
}
export async function getDocumentRangeFormattingEditsUntilResult(
workerService: IEditorWorkerService,
model: ITextModel,
range: Range,
options: FormattingOptions,
mode: FormatMode,
token: CancellationToken
): Promise<TextEdit[] | undefined | null> {
): Promise<TextEdit[] | undefined> {
const providers = DocumentRangeFormattingEditProviderRegistry.ordered(model);
/* __GDPR__
"formatterInfo" : {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
for (const provider of providers) {
let rawEdits = await Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);
if (isNonEmptyArray(rawEdits)) {
return await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
}
*/
telemetryService.publicLog('formatterInfo', {
type: 'range',
language: model.getLanguageIdentifier().language,
count: providers.length,
extensions: providers.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
invokeFormatterCallback(providers, model, mode | FormatKind.Range);
return first(providers.map(provider => () => {
return Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);
}), isNonEmptyArray).then(edits => {
// break edits into smaller edits
return workerService.computeMoreMinimalEdits(model.uri, edits);
});
}
return undefined;
}
export function getDocumentFormattingEdits(
telemetryService: ITelemetryService,
export async function getDocumentFormattingEditsUntilResult(
workerService: IEditorWorkerService,
model: ITextModel,
options: FormattingOptions,
mode: FormatMode,
token: CancellationToken
): Promise<TextEdit[] | null | undefined> {
): Promise<TextEdit[] | undefined> {
const docFormattingProviders = DocumentFormattingEditProviderRegistry.ordered(model);
/* __GDPR__
"formatterInfo" : {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
const providers = getRealAndSyntheticDocumentFormattersOrdered(model);
for (const provider of providers) {
let rawEdits = await Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);
if (isNonEmptyArray(rawEdits)) {
return await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
}
*/
telemetryService.publicLog('formatterInfo', {
type: 'document',
language: model.getLanguageIdentifier().language,
count: docFormattingProviders.length,
extensions: docFormattingProviders.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
if (docFormattingProviders.length > 0) {
return first(docFormattingProviders.map(provider => () => {
// first with result wins...
return Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);
}), isNonEmptyArray).then(edits => {
// break edits into smaller edits
return workerService.computeMoreMinimalEdits(model.uri, edits);
});
} else {
// try range formatters when no document formatter is registered
return getDocumentRangeFormattingEdits(telemetryService, workerService, model, model.getFullModelRange(), options, mode | FormatKind.Document, token);
}
return undefined;
}
export function getOnTypeFormattingEdits(
telemetryService: ITelemetryService,
workerService: IEditorWorkerService,
model: ITextModel,
position: Position,
@@ -144,21 +264,6 @@ export function getOnTypeFormattingEdits(
const providers = OnTypeFormattingEditProviderRegistry.ordered(model);
/* __GDPR__
"formatterInfo" : {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('formatterInfo', {
type: 'ontype',
language: model.getLanguageIdentifier().language,
count: providers.length,
extensions: providers.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
if (providers.length === 0) {
return Promise.resolve(undefined);
}
@@ -181,7 +286,7 @@ registerLanguageCommand('_executeFormatRangeProvider', function (accessor, args)
if (!model) {
throw illegalArgument('resource');
}
return getDocumentRangeFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, Range.lift(range), options, FormatMode.Auto, CancellationToken.None);
return getDocumentRangeFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, Range.lift(range), options, CancellationToken.None);
});
registerLanguageCommand('_executeFormatDocumentProvider', function (accessor, args) {
@@ -194,7 +299,7 @@ registerLanguageCommand('_executeFormatDocumentProvider', function (accessor, ar
throw illegalArgument('resource');
}
return getDocumentFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, options, FormatMode.Auto, CancellationToken.None);
return getDocumentFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, options, CancellationToken.None);
});
registerLanguageCommand('_executeFormatOnTypeProvider', function (accessor, args) {
@@ -207,5 +312,5 @@ registerLanguageCommand('_executeFormatOnTypeProvider', function (accessor, args
throw illegalArgument('resource');
}
return getOnTypeFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, Position.lift(position), ch, options);
return getOnTypeFormattingEdits(accessor.get(IEditorWorkerService), model, Position.lift(position), ch, options);
});

View File

@@ -3,122 +3,27 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { alert } from 'vs/base/browser/ui/aria/aria';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState';
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { DocumentRangeFormattingEditProviderRegistry, FormattingOptions, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
import { DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits, FormatMode } from 'vs/editor/contrib/format/format';
import { getOnTypeFormattingEdits, formatDocumentWithProvider, formatDocumentRangeWithProvider, alertFormattingEdits, getRealAndSyntheticDocumentFormattersOrdered } from 'vs/editor/contrib/format/format';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import * as nls from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
function alertFormattingEdits(edits: ISingleEditOperation[]): void {
edits = edits.filter(edit => edit.range);
if (!edits.length) {
return;
}
let { range } = edits[0];
for (let i = 1; i < edits.length; i++) {
range = Range.plusRange(range, edits[i].range);
}
const { startLineNumber, endLineNumber } = range;
if (startLineNumber === endLineNumber) {
if (edits.length === 1) {
alert(nls.localize('hint11', "Made 1 formatting edit on line {0}", startLineNumber));
} else {
alert(nls.localize('hintn1', "Made {0} formatting edits on line {1}", edits.length, startLineNumber));
}
} else {
if (edits.length === 1) {
alert(nls.localize('hint1n', "Made 1 formatting edit between lines {0} and {1}", startLineNumber, endLineNumber));
} else {
alert(nls.localize('hintnn', "Made {0} formatting edits between lines {1} and {2}", edits.length, startLineNumber, endLineNumber));
}
}
}
const enum FormatRangeType {
Full,
Selection,
}
function formatDocumentRange(
telemetryService: ITelemetryService,
workerService: IEditorWorkerService,
editor: IActiveCodeEditor,
rangeOrRangeType: Range | FormatRangeType,
options: FormattingOptions,
token: CancellationToken
): Promise<void> {
const state = new EditorState(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
const model = editor.getModel();
let range: Range;
if (rangeOrRangeType === FormatRangeType.Full) {
// full
range = model.getFullModelRange();
} else if (rangeOrRangeType === FormatRangeType.Selection) {
// selection or line (when empty)
range = editor.getSelection();
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.endLineNumber, model.getLineMaxColumn(range.endLineNumber));
}
} else {
// as is
range = rangeOrRangeType;
}
return getDocumentRangeFormattingEdits(telemetryService, workerService, model, range, options, FormatMode.Manual, token).then(edits => {
// make edit only when the editor didn't change while
// computing and only when there are edits
if (state.validate(editor) && isNonEmptyArray(edits)) {
FormattingEdit.execute(editor, edits);
alertFormattingEdits(edits);
editor.focus();
editor.revealPositionInCenterIfOutsideViewport(editor.getPosition(), editorCommon.ScrollType.Immediate);
}
});
}
function formatDocument(telemetryService: ITelemetryService, workerService: IEditorWorkerService, editor: IActiveCodeEditor, options: FormattingOptions, token: CancellationToken): Promise<void> {
const allEdits: ISingleEditOperation[] = [];
const state = new EditorState(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
return getDocumentFormattingEdits(telemetryService, workerService, editor.getModel(), options, FormatMode.Manual, token).then(edits => {
// make edit only when the editor didn't change while
// computing and only when there are edits
if (state.validate(editor) && isNonEmptyArray(edits)) {
FormattingEdit.execute(editor, edits);
alertFormattingEdits(allEdits);
editor.pushUndoStop();
editor.focus();
editor.revealPositionInCenterIfOutsideViewport(editor.getPosition(), editorCommon.ScrollType.Immediate);
}
});
}
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { onUnexpectedError } from 'vs/base/common/errors';
class FormatOnType implements editorCommon.IEditorContribution {
@@ -130,17 +35,25 @@ class FormatOnType implements editorCommon.IEditorContribution {
constructor(
editor: ICodeEditor,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IEditorWorkerService private readonly _workerService: IEditorWorkerService
) {
this._editor = editor;
this._callOnDispose.push(editor.onDidChangeConfiguration(() => this.update()));
this._callOnDispose.push(editor.onDidChangeModel(() => this.update()));
this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this.update()));
this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this.update, this));
this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModel(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update()));
this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this));
}
private update(): void {
getId(): string {
return FormatOnType.ID;
}
dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
private _update(): void {
// clean up
this._callOnModel = dispose(this._callOnModel);
@@ -171,12 +84,12 @@ class FormatOnType implements editorCommon.IEditorContribution {
this._callOnModel.push(this._editor.onDidType((text: string) => {
let lastCharCode = text.charCodeAt(text.length - 1);
if (triggerChars.has(lastCharCode)) {
this.trigger(String.fromCharCode(lastCharCode));
this._trigger(String.fromCharCode(lastCharCode));
}
}));
}
private trigger(ch: string): void {
private _trigger(ch: string): void {
if (!this._editor.hasModel()) {
return;
}
@@ -214,7 +127,6 @@ class FormatOnType implements editorCommon.IEditorContribution {
});
getOnTypeFormattingEdits(
this._telemetryService,
this._workerService,
model,
position,
@@ -238,42 +150,41 @@ class FormatOnType implements editorCommon.IEditorContribution {
throw err;
});
}
public getId(): string {
return FormatOnType.ID;
}
public dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
}
class FormatOnPaste implements editorCommon.IEditorContribution {
private static readonly ID = 'editor.contrib.formatOnPaste';
private callOnDispose: IDisposable[];
private callOnModel: IDisposable[];
private _callOnDispose: IDisposable[];
private _callOnModel: IDisposable[];
constructor(
private readonly editor: ICodeEditor,
@IEditorWorkerService private readonly workerService: IEditorWorkerService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
this.callOnDispose = [];
this.callOnModel = [];
this._callOnDispose = [];
this._callOnModel = [];
this.callOnDispose.push(editor.onDidChangeConfiguration(() => this.update()));
this.callOnDispose.push(editor.onDidChangeModel(() => this.update()));
this.callOnDispose.push(editor.onDidChangeModelLanguage(() => this.update()));
this.callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this.update, this));
this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModel(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update()));
this._callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this));
}
private update(): void {
getId(): string {
return FormatOnPaste.ID;
}
dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
private _update(): void {
// clean up
this.callOnModel = dispose(this.callOnModel);
this._callOnModel = dispose(this._callOnModel);
// we are disabled
if (!this.editor.getConfiguration().contribInfo.formatOnPaste) {
@@ -285,53 +196,41 @@ class FormatOnPaste implements editorCommon.IEditorContribution {
return;
}
let model = this.editor.getModel();
// no support
if (!DocumentRangeFormattingEditProviderRegistry.has(model)) {
// no formatter
if (!DocumentRangeFormattingEditProviderRegistry.has(this.editor.getModel())) {
return;
}
this.callOnModel.push(this.editor.onDidPaste((range: Range) => {
this.trigger(range);
}));
this._callOnModel.push(this.editor.onDidPaste(range => this._trigger(range)));
}
private trigger(range: Range): void {
private _trigger(range: Range): void {
if (!this.editor.hasModel()) {
return;
}
if (this.editor.getSelections().length > 1) {
return;
}
const model = this.editor.getModel();
formatDocumentRange(this.telemetryService, this.workerService, this.editor, range, model.getFormattingOptions(), CancellationToken.None);
}
public getId(): string {
return FormatOnPaste.ID;
}
public dispose(): void {
this.callOnDispose = dispose(this.callOnDispose);
this.callOnModel = dispose(this.callOnModel);
const provider = DocumentRangeFormattingEditProviderRegistry.ordered(this.editor.getModel());
if (provider.length !== 1) {
// print status in n>1 case?
return;
}
this._instantiationService.invokeFunction(formatDocumentRangeWithProvider, provider[0], this.editor, range, CancellationToken.None).catch(onUnexpectedError);
}
}
export class FormatDocumentAction extends EditorAction {
class FormatDocumentAction extends EditorAction {
constructor() {
super({
id: 'editor.action.formatDocument',
label: nls.localize('formatDocument.label', "Format Document"),
alias: 'Format Document',
precondition: EditorContextKeys.writable,
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider, EditorContextKeys.hasMultipleDocumentFormattingProvider.toNegated()),
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider),
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
// secondary: [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D)],
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I },
weight: KeybindingWeight.EditorContrib
},
@@ -343,26 +242,29 @@ export class FormatDocumentAction extends EditorAction {
});
}
run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> | void {
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel()) {
return;
}
const workerService = accessor.get(IEditorWorkerService);
const telemetryService = accessor.get(ITelemetryService);
return formatDocument(telemetryService, workerService, editor, editor.getModel().getFormattingOptions(), CancellationToken.None);
const instaService = accessor.get(IInstantiationService);
const model = editor.getModel();
const [provider] = getRealAndSyntheticDocumentFormattersOrdered(model);
if (provider) {
await instaService.invokeFunction(formatDocumentWithProvider, provider, editor, CancellationToken.None);
}
}
}
export class FormatSelectionAction extends EditorAction {
class FormatSelectionAction extends EditorAction {
constructor() {
super({
id: 'editor.action.formatSelection',
label: nls.localize('formatSelection.label', "Format Selection"),
alias: 'Format Code',
precondition: ContextKeyExpr.and(EditorContextKeys.writable),
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.toNegated()),
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentSelectionFormattingProvider),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F),
weight: KeybindingWeight.EditorContrib
},
@@ -374,13 +276,19 @@ export class FormatSelectionAction extends EditorAction {
});
}
run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> | void {
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel()) {
return;
}
const workerService = accessor.get(IEditorWorkerService);
const telemetryService = accessor.get(ITelemetryService);
return formatDocumentRange(telemetryService, workerService, editor, FormatRangeType.Selection, editor.getModel().getFormattingOptions(), CancellationToken.None);
const instaService = accessor.get(IInstantiationService);
const [best] = DocumentRangeFormattingEditProviderRegistry.ordered(editor.getModel());
if (best) {
let range: Range = editor.getSelection();
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.startLineNumber, editor.getModel().getLineMaxColumn(range.startLineNumber));
}
await instaService.invokeFunction(formatDocumentRangeWithProvider, best, editor, range, CancellationToken.None);
}
}
}
@@ -391,17 +299,15 @@ registerEditorAction(FormatSelectionAction);
// this is the old format action that does both (format document OR format selection)
// and we keep it here such that existing keybinding configurations etc will still work
CommandsRegistry.registerCommand('editor.action.format', accessor => {
CommandsRegistry.registerCommand('editor.action.format', async accessor => {
const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
if (!editor || !editor.hasModel()) {
return undefined;
return;
}
const workerService = accessor.get(IEditorWorkerService);
const telemetryService = accessor.get(ITelemetryService);
const commandService = accessor.get(ICommandService);
if (editor.getSelection().isEmpty()) {
return formatDocument(telemetryService, workerService, editor, editor.getModel().getFormattingOptions(), CancellationToken.None);
await commandService.executeCommand('editor.action.formatDocument');
} else {
return formatDocumentRange(telemetryService, workerService, editor, FormatRangeType.Selection, editor.getModel().getFormattingOptions(), CancellationToken.None);
await commandService.executeCommand('editor.action.formatSelection');
}
});

View File

@@ -203,8 +203,8 @@ export class MarkerController implements editorCommon.IEditorContribution {
}
private readonly _editor: ICodeEditor;
private _model: MarkerModel | null;
private _widget: MarkerNavigationWidget | null;
private _model: MarkerModel | null = null;
private _widget: MarkerNavigationWidget | null = null;
private readonly _widgetVisible: IContextKey<boolean>;
private _disposeOnClose: IDisposable[] = [];

View File

@@ -21,7 +21,7 @@ export class MoveLinesCommand implements ICommand {
private readonly _autoIndent: boolean;
private _selectionId: string;
private _moveEndPositionDown: boolean;
private _moveEndPositionDown?: boolean;
private _moveEndLineSelectionShrink: boolean;
constructor(selection: Selection, isMovingDown: boolean, autoIndent: boolean) {

View File

@@ -196,10 +196,9 @@ suite('Editor Contrib - Line Operations', () => {
const endOfNonono = new Selection(5, 11, 5, 11);
editor.setSelections([beforeSecondWasoSelection, endOfBCCSelection, endOfNonono]);
let selections;
deleteAllLeftAction.run(null!, editor);
selections = editor.getSelections();
let selections = editor.getSelections()!;
assert.equal(model.getLineContent(2), '');
assert.equal(model.getLineContent(3), ' waso waso');
@@ -227,7 +226,7 @@ suite('Editor Contrib - Line Operations', () => {
], [5, 1, 5, 1]);
deleteAllLeftAction.run(null!, editor);
selections = editor.getSelections();
selections = editor.getSelections()!;
assert.equal(model.getLineContent(1), 'hi my name is Carlos Matos waso waso');
assert.equal(selections.length, 2);

View File

@@ -21,6 +21,7 @@ import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet } from './sni
import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import * as colors from 'vs/platform/theme/common/colorRegistry';
import { withNullAsUndefined } from 'vs/base/common/types';
registerThemingParticipant((theme, collector) => {
@@ -281,7 +282,7 @@ export class OneSnippet {
let result: Range | undefined;
const model = this._editor.getModel();
this._placeholderDecorations.forEach((decorationId) => {
const placeholderRange = model.getDecorationRange(decorationId) || undefined;
const placeholderRange = withNullAsUndefined(model.getDecorationRange(decorationId));
if (!result) {
result = placeholderRange;
} else {

View File

@@ -18,8 +18,8 @@ export class SuggestAlternatives {
private _index: number;
private _model: CompletionModel | undefined;
private _acceptNext: ((selected: ISelectedSuggestion) => any) | undefined;
private _listener: IDisposable;
private _ignore: boolean;
private _listener: IDisposable | undefined;
private _ignore: boolean | undefined;
constructor(
private readonly _editor: ICodeEditor,