Merge from vscode 966b87dd4013be1a9c06e2b8334522ec61905cc2 (#4696)

This commit is contained in:
Anthony Dresser
2019-03-26 11:43:38 -07:00
committed by GitHub
parent b1393ae615
commit 0d8ef9583b
268 changed files with 5947 additions and 3422 deletions

View File

@@ -18,8 +18,6 @@ export const ID_INDENT_PROVIDER = 'indent';
export class IndentRangeProvider implements RangeProvider {
readonly id = ID_INDENT_PROVIDER;
readonly decorations;
constructor(private readonly editorModel: ITextModel) {
}

View File

@@ -22,6 +22,9 @@ 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { ILabelService } from 'vs/platform/label/common/label';
export function alertFormattingEdits(edits: ISingleEditOperation[]): void {
@@ -83,6 +86,32 @@ export function getRealAndSyntheticDocumentFormattersOrdered(model: ITextModel):
return result;
}
export async function formatDocumentRangeWithFirstProvider(
accessor: ServicesAccessor,
editorOrModel: ITextModel | IActiveCodeEditor,
range: Range,
token: CancellationToken
): Promise<boolean> {
const instaService = accessor.get(IInstantiationService);
const statusBarService = accessor.get(IStatusbarService);
const labelService = accessor.get(ILabelService);
const model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;
const [best, ...rest] = DocumentRangeFormattingEditProviderRegistry.ordered(model);
if (!best) {
return false;
}
const ret = await instaService.invokeFunction(formatDocumentRangeWithProvider, best, editorOrModel, range, token);
if (rest.length > 0) {
statusBarService.setStatusMessage(
nls.localize('random.pick', "$(tasklist) Formatted '{0}' with '{1}'", labelService.getUriLabel(model.uri, { relative: true }), best.displayName),
5 * 1000
);
}
return ret;
}
export async function formatDocumentRangeWithProvider(
accessor: ServicesAccessor,
provider: DocumentRangeFormattingEditProvider,
@@ -152,6 +181,31 @@ export async function formatDocumentRangeWithProvider(
return true;
}
export async function formatDocumentWithFirstProvider(
accessor: ServicesAccessor,
editorOrModel: ITextModel | IActiveCodeEditor,
token: CancellationToken
): Promise<boolean> {
const instaService = accessor.get(IInstantiationService);
const statusBarService = accessor.get(IStatusbarService);
const labelService = accessor.get(ILabelService);
const model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;
const [best, ...rest] = getRealAndSyntheticDocumentFormattersOrdered(model);
if (!best) {
return false;
}
const ret = await instaService.invokeFunction(formatDocumentWithProvider, best, editorOrModel, token);
if (rest.length > 0) {
statusBarService.setStatusMessage(
nls.localize('random.pick', "$(tasklist) Formatted '{0}' with '{1}'", labelService.getUriLabel(model.uri, { relative: true }), best.displayName),
5 * 1000
);
}
return ret;
}
export async function formatDocumentWithProvider(
accessor: ServicesAccessor,
provider: DocumentFormattingEditProvider,

View File

@@ -16,7 +16,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { getOnTypeFormattingEdits, formatDocumentWithProvider, formatDocumentRangeWithProvider, alertFormattingEdits, getRealAndSyntheticDocumentFormattersOrdered } from 'vs/editor/contrib/format/format';
import { getOnTypeFormattingEdits, alertFormattingEdits, formatDocumentRangeWithFirstProvider, formatDocumentWithFirstProvider } from 'vs/editor/contrib/format/format';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import * as nls from 'vs/nls';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
@@ -211,12 +211,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution {
if (this.editor.getSelections().length > 1) {
return;
}
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);
this._instantiationService.invokeFunction(formatDocumentRangeWithFirstProvider, this.editor, range, CancellationToken.None).catch(onUnexpectedError);
}
}
@@ -227,7 +222,7 @@ class FormatDocumentAction extends EditorAction {
id: 'editor.action.formatDocument',
label: nls.localize('formatDocument.label', "Format Document"),
alias: 'Format Document',
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider, EditorContextKeys.hasMultipleDocumentFormattingProvider.toNegated()),
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider),
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider),
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
@@ -243,14 +238,9 @@ class FormatDocumentAction extends EditorAction {
}
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel()) {
return;
}
const instaService = accessor.get(IInstantiationService);
const model = editor.getModel();
const [provider] = getRealAndSyntheticDocumentFormattersOrdered(model);
if (provider) {
await instaService.invokeFunction(formatDocumentWithProvider, provider, editor, CancellationToken.None);
if (editor.hasModel()) {
const instaService = accessor.get(IInstantiationService);
await instaService.invokeFunction(formatDocumentWithFirstProvider, editor, CancellationToken.None);
}
}
}
@@ -262,7 +252,7 @@ class FormatSelectionAction extends EditorAction {
id: 'editor.action.formatSelection',
label: nls.localize('formatSelection.label', "Format Selection"),
alias: 'Format Code',
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.toNegated()),
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider),
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentSelectionFormattingProvider),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F),
@@ -281,14 +271,12 @@ class FormatSelectionAction extends EditorAction {
return;
}
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);
const model = editor.getModel();
let range: Range = editor.getSelection();
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber));
}
await instaService.invokeFunction(formatDocumentRangeWithFirstProvider, editor, range, CancellationToken.None);
}
}

View File

@@ -41,6 +41,7 @@ import { Action } from 'vs/base/common/actions';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { IModeService } from 'vs/editor/common/services/modeService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
const $ = dom.$;
@@ -385,10 +386,10 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
model.guessColorPresentation(color, originalText);
const updateEditorModel = () => {
let textEdits;
let newRange;
let textEdits: IIdentifiedSingleEditOperation[];
let newRange: Range;
if (model.presentation.textEdit) {
textEdits = [model.presentation.textEdit];
textEdits = [model.presentation.textEdit as IIdentifiedSingleEditOperation];
newRange = new Range(
model.presentation.textEdit.range.startLineNumber,
model.presentation.textEdit.range.startColumn,
@@ -405,7 +406,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
this._editor.executeEdits('colorpicker', textEdits);
if (model.presentation.additionalTextEdits) {
textEdits = [...model.presentation.additionalTextEdits];
textEdits = [...model.presentation.additionalTextEdits as IIdentifiedSingleEditOperation[]];
this._editor.executeEdits('colorpicker', textEdits);
this.hide();
}

View File

@@ -18,7 +18,38 @@ import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeE
import { IOptions, IStyles, ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import * as nls from 'vs/nls';
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export const IPeekViewService = createDecorator<IPeekViewService>('IPeekViewService');
export interface IPeekViewService {
_serviceBrand: any;
addExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void;
}
registerSingleton(IPeekViewService, class implements IPeekViewService {
_serviceBrand: any;
private _widgets = new Map<ICodeEditor, { widget: PeekViewWidget, listener: IDisposable }>();
addExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void {
const existing = this._widgets.get(editor);
if (existing) {
existing.listener.dispose();
existing.widget.dispose();
}
const remove = () => {
const data = this._widgets.get(editor);
if (data && data.widget === widget) {
data.listener.dispose();
this._widgets.delete(editor);
}
};
this._widgets.set(editor, { widget, listener: widget.onDidClose(remove) });
}
});
export namespace PeekContext {
export const inPeekEditor = new RawContextKey<boolean>('inReferenceSearchEditor', true);

View File

@@ -102,6 +102,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri
this._widget = this._instantiationService.createInstance(ReferenceWidget, this._editor, this._defaultTreeKeyboardSupport, data);
this._widget.setTitle(nls.localize('labelLoading', "Loading..."));
this._widget.show(range);
this._disposables.push(this._widget.onDidClose(() => {
modelPromise.cancel();
if (this._widget) {

View File

@@ -5,7 +5,7 @@
import * as dom from 'vs/base/browser/dom';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { ISashEvent, IVerticalSashLayoutProvider, Sash } from 'vs/base/browser/ui/sash/sash';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable, IReference } from 'vs/base/common/lifecycle';
@@ -29,12 +29,14 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
import { activeContrastBorder, contrastBorder, registerColor } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { PeekViewWidget } from './peekViewWidget';
import { PeekViewWidget, IPeekViewService } from './peekViewWidget';
import { FileReferences, OneReference, ReferencesModel } from './referencesModel';
import { ITreeRenderer, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { FuzzyScore } from 'vs/base/common/filters';
import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
class DecorationsManager implements IDisposable {
@@ -155,72 +157,6 @@ class DecorationsManager implements IDisposable {
}
}
class VSash {
private _disposables: IDisposable[] = [];
private _sash: Sash;
private _ratio: number;
private _height: number;
private _width: number;
private _onDidChangePercentages = new Emitter<VSash>();
constructor(container: HTMLElement, ratio: number) {
this._ratio = ratio;
this._sash = new Sash(container, <IVerticalSashLayoutProvider>{
getVerticalSashLeft: () => this._width * this._ratio,
getVerticalSashHeight: () => this._height
});
// compute the current widget clientX postion since
// the sash works with clientX when dragging
let clientX: number;
this._disposables.push(this._sash.onDidStart((e: ISashEvent) => {
clientX = e.startX - (this._width * this.ratio);
}));
this._disposables.push(this._sash.onDidChange((e: ISashEvent) => {
// compute the new position of the sash and from that
// compute the new ratio that we are using
let newLeft = e.currentX - clientX;
if (newLeft > 20 && newLeft + 20 < this._width) {
this._ratio = newLeft / this._width;
this._sash.layout();
this._onDidChangePercentages.fire(this);
}
}));
}
dispose() {
this._sash.dispose();
this._onDidChangePercentages.dispose();
dispose(this._disposables);
}
get onDidChangePercentages() {
return this._onDidChangePercentages.event;
}
set width(value: number) {
this._width = value;
this._sash.layout();
}
set height(value: number) {
this._height = value;
this._sash.layout();
}
get percentages() {
let left = 100 * this._ratio;
let right = 100 - left;
return [`${left}%`, `${right}%`];
}
get ratio() {
return this._ratio;
}
}
export interface LayoutData {
ratio: number;
heightInLines: number;
@@ -248,14 +184,14 @@ export class ReferenceWidget extends PeekViewWidget {
private _tree: WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>;
private _treeContainer: HTMLElement;
private _sash: VSash;
// private _sash: VSash;
private _splitView: SplitView;
private _preview: ICodeEditor;
private _previewModelReference: IReference<ITextEditorModel>;
private _previewNotAvailableMessage: TextModel;
private _previewContainer: HTMLElement;
private _messageContainer: HTMLElement;
private height: number | undefined;
private width: number | undefined;
private _dim: dom.Dimension = { height: 0, width: 0 };
constructor(
editor: ICodeEditor,
@@ -264,15 +200,25 @@ export class ReferenceWidget extends PeekViewWidget {
@IThemeService themeService: IThemeService,
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IPeekViewService private readonly _peekViewService: IPeekViewService,
@ILabelService private readonly _uriLabel: ILabelService
) {
super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true });
this._applyTheme(themeService.getTheme());
this._callOnDispose.push(themeService.onThemeChange(this._applyTheme.bind(this)));
this._peekViewService.addExclusiveWidget(editor, this);
this.create();
}
dispose(): void {
this.setModel(undefined);
this._callOnDispose = dispose(this._callOnDispose);
dispose<IDisposable>(this._preview, this._previewNotAvailableMessage, this._tree, this._previewModelReference);
this._splitView.dispose();
super.dispose();
}
private _applyTheme(theme: ITheme) {
const borderColor = theme.getColor(peekViewBorder) || Color.transparent;
this.style({
@@ -284,13 +230,6 @@ export class ReferenceWidget extends PeekViewWidget {
});
}
public dispose(): void {
this.setModel(undefined);
this._callOnDispose = dispose(this._callOnDispose);
dispose<IDisposable>(this._preview, this._previewNotAvailableMessage, this._tree, this._sash, this._previewModelReference);
super.dispose();
}
get onDidSelectReference(): Event<SelectionEvent> {
return this._onDidSelectReference.event;
}
@@ -321,6 +260,8 @@ export class ReferenceWidget extends PeekViewWidget {
this._messageContainer = dom.append(containerElement, dom.$('div.messages'));
dom.hide(this._messageContainer);
this._splitView = new SplitView(containerElement, { orientation: Orientation.HORIZONTAL });
// editor
this._previewContainer = dom.append(containerElement, dom.$('div.preview.inline'));
let options: IEditorOptions = {
@@ -342,25 +283,8 @@ export class ReferenceWidget extends PeekViewWidget {
dom.hide(this._previewContainer);
this._previewNotAvailableMessage = TextModel.createFromString(nls.localize('missingPreviewMessage', "no preview available"));
// sash
this._sash = new VSash(containerElement, this.layoutData.ratio || 0.8);
this._sash.onDidChangePercentages(() => {
let [left, right] = this._sash.percentages;
this._previewContainer.style.width = left;
this._treeContainer.style.width = right;
this._preview.layout();
this._tree.layout(this.height, this.width && this.width * (1 - this._sash.ratio));
this.layoutData.ratio = this._sash.ratio;
});
// tree
this._treeContainer = dom.append(containerElement, dom.$('div.ref-tree.inline'));
const renderers = [
this._instantiationService.createInstance(FileReferencesRenderer),
this._instantiationService.createInstance(OneReferenceRenderer),
];
const treeOptions: IAsyncDataTreeOptions<TreeElement, FuzzyScore> = {
ariaLabel: nls.localize('treeAriaLabel', "References"),
keyboardSupport: this._defaultTreeKeyboardSupport,
@@ -368,20 +292,48 @@ export class ReferenceWidget extends PeekViewWidget {
keyboardNavigationLabelProvider: this._instantiationService.createInstance(StringRepresentationProvider),
identityProvider: new IdentityProvider()
};
const treeDataSource = this._instantiationService.createInstance(DataSource);
this._tree = this._instantiationService.createInstance<HTMLElement, IListVirtualDelegate<TreeElement>, ITreeRenderer<any, FuzzyScore, any>[], IAsyncDataSource<ReferencesModel | FileReferences, TreeElement>, IAsyncDataTreeOptions<TreeElement, FuzzyScore>, WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>>(
WorkbenchAsyncDataTree,
this._treeContainer,
new Delegate(),
renderers,
treeDataSource,
[
this._instantiationService.createInstance(FileReferencesRenderer),
this._instantiationService.createInstance(OneReferenceRenderer),
],
this._instantiationService.createInstance(DataSource),
treeOptions
);
ctxReferenceWidgetSearchTreeFocused.bindTo(this._tree.contextKeyService);
// split stuff
this._splitView.addView({
onDidChange: Event.None,
element: this._previewContainer,
minimumSize: 200,
maximumSize: Number.MAX_VALUE,
layout: (width) => {
this._preview.layout({ height: this._dim.height, width });
}
}, Sizing.Distribute);
this._splitView.addView({
onDidChange: Event.None,
element: this._treeContainer,
minimumSize: 100,
maximumSize: Number.MAX_VALUE,
layout: (width) => {
this._treeContainer.style.height = `${this._dim.height}px`;
this._treeContainer.style.width = `${width}px`;
this._tree.layout(this._dim.height, width);
}
}, Sizing.Distribute);
this._splitView.onDidSashChange(() => {
if (this._dim.width) {
this.layoutData.ratio = this._splitView.getViewSize(0) / this._dim.width;
}
}, undefined, this._disposables);
// listen on selection and focus
let onEvent = (element: any, kind: 'show' | 'goto' | 'side') => {
if (element instanceof OneReference) {
@@ -428,36 +380,18 @@ export class ReferenceWidget extends PeekViewWidget {
dom.hide(this._treeContainer);
}
protected _doLayoutBody(heightInPixel: number, widthInPixel: number): void {
super._doLayoutBody(heightInPixel, widthInPixel);
this.height = heightInPixel;
this.width = widthInPixel;
const height = heightInPixel + 'px';
this._sash.height = heightInPixel;
this._sash.width = widthInPixel;
// set height/width
const [left, right] = this._sash.percentages;
this._previewContainer.style.height = height;
this._previewContainer.style.width = left;
this._treeContainer.style.height = height;
this._treeContainer.style.width = right;
// forward
this._tree.layout(heightInPixel, widthInPixel * (1 - this._sash.ratio));
this._preview.layout();
// store layout data
this.layoutData = {
heightInLines: this._viewZone ? this._viewZone.heightInLines : 0,
ratio: this._sash.ratio
};
protected _onWidth(width: number) {
if (this._dim) {
this._doLayoutBody(this._dim.height, width);
}
}
public _onWidth(widthInPixel: number): void {
this._sash.width = widthInPixel;
this._preview.layout();
protected _doLayoutBody(heightInPixel: number, widthInPixel: number): void {
super._doLayoutBody(heightInPixel, widthInPixel);
this._dim = { height: heightInPixel, width: widthInPixel };
this.layoutData.heightInLines = this._viewZone ? this._viewZone.heightInLines : this.layoutData.heightInLines;
this._splitView.layout(widthInPixel);
this._splitView.resizeView(0, widthInPixel * this.layoutData.ratio);
}
public setSelection(selection: OneReference): Promise<any> {
@@ -522,8 +456,7 @@ export class ReferenceWidget extends PeekViewWidget {
dom.addClass(this.container, 'results-loaded');
dom.show(this._treeContainer);
dom.show(this._previewContainer);
this._preview.layout();
this._tree.layout();
this._splitView.layout(this._dim.width);
this.focus();
// pick input and a reference to begin with

View File

@@ -116,7 +116,7 @@ export class RenameInputField implements IContentWidget, IDisposable {
}
private _currentAcceptInput: (() => void) | null = null;
private _currentCancelInput: ((focusEditor) => void) | null = null;
private _currentCancelInput: ((focusEditor: boolean) => void) | null = null;
public acceptInput(): void {
if (this._currentAcceptInput) {
@@ -144,7 +144,7 @@ export class RenameInputField implements IContentWidget, IDisposable {
this._hide();
};
return new Promise<string>(resolve => {
return new Promise<string | boolean>(resolve => {
this._currentCancelInput = (focusEditor) => {
this._currentAcceptInput = null;