未验证 提交 f5665378 编写于 作者: C Connor Peet

testing: start of diff peek view

上级 09d99f7d
......@@ -1052,7 +1052,7 @@ export interface IDiffEditor extends editorCommon.IEditor {
/**
*@internal
*/
export function isCodeEditor(thing: any): thing is ICodeEditor {
export function isCodeEditor(thing: unknown): thing is ICodeEditor {
if (thing && typeof (<ICodeEditor>thing).getEditorType === 'function') {
return (<ICodeEditor>thing).getEditorType() === editorCommon.EditorType.ICodeEditor;
} else {
......@@ -1063,7 +1063,7 @@ export function isCodeEditor(thing: any): thing is ICodeEditor {
/**
*@internal
*/
export function isDiffEditor(thing: any): thing is IDiffEditor {
export function isDiffEditor(thing: unknown): thing is IDiffEditor {
if (thing && typeof (<IDiffEditor>thing).getEditorType === 'function') {
return (<IDiffEditor>thing).getEditorType() === editorCommon.EditorType.IDiffEditor;
} else {
......@@ -1074,8 +1074,8 @@ export function isDiffEditor(thing: any): thing is IDiffEditor {
/**
*@internal
*/
export function isCompositeEditor(thing: any): thing is editorCommon.ICompositeCodeEditor {
return thing
export function isCompositeEditor(thing: unknown): thing is editorCommon.ICompositeCodeEditor {
return !!thing
&& typeof thing === 'object'
&& typeof (<editorCommon.ICompositeCodeEditor>thing).onDidChangeActiveEditor === 'function';
......@@ -1084,7 +1084,7 @@ export function isCompositeEditor(thing: any): thing is editorCommon.ICompositeC
/**
*@internal
*/
export function getCodeEditor(thing: any): ICodeEditor | null {
export function getCodeEditor(thing: unknown): ICodeEditor | null {
if (isCodeEditor(thing)) {
return thing;
}
......
......@@ -430,7 +430,7 @@ class DocumentSymbolsOutlineCreator implements IOutlineCreator<IEditorPane, Docu
const control = pane.getControl();
let editor: ICodeEditor | undefined;
if (isCodeEditor(control)) {
editor = control as ICodeEditor;
editor = control;
} else if (isDiffEditor(control)) {
editor = control.getModifiedEditor();
}
......
......@@ -3,6 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { localize } from 'vs/nls';
import { registerAction2 } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
......@@ -15,12 +18,14 @@ import { Extensions as ViewContainerExtensions, IViewContainersRegistry, IViewsR
import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons';
import { ITestingCollectionService, TestingCollectionService } from 'vs/workbench/contrib/testing/browser/testingCollectionService';
import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView';
import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer';
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestMessage, TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection';
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { TestService } from 'vs/workbench/contrib/testing/common/testServiceImpl';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as Action from './testExplorerActions';
registerSingleton(ITestService, TestService);
......@@ -77,6 +82,8 @@ registerAction2(Action.TestingGroupByLocationAction);
registerAction2(Action.TestingGroupByStatusAction);
registerAction2(Action.RefreshTestsAction);
registerEditorContribution(Testing.OutputPeekContributionId, TestingOutputPeekController);
CommandsRegistry.registerCommand({
id: 'vscode.runTests',
handler: async (accessor: ServicesAccessor, tests: TestIdWithProvider[]) => {
......@@ -92,3 +99,25 @@ CommandsRegistry.registerCommand({
testService.runTests({ debug: true, tests: tests.filter(t => t.providerId && t.testId) });
}
});
CommandsRegistry.registerCommand({
id: 'vscode.revealTestMessage',
handler: async (accessor: ServicesAccessor, message: ITestMessage) => {
if (!message.location) {
console.warn('Cannot reveal a test message without an associated location');
return;
}
const pane = await accessor.get(IEditorService).openEditor({
resource: URI.revive(message.location.uri),
options: { selection: message.location.range }
});
const control = pane?.getControl();
if (!isCodeEditor(control)) {
return;
}
TestingOutputPeekController.get(control).show(message);
}
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { Color } from 'vs/base/common/color';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { TextModel } from 'vs/editor/common/model/textModel';
import { IPeekViewService, peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, PeekViewWidget } from 'vs/editor/contrib/peekView/peekView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { EditorModel } from 'vs/workbench/common/editor';
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
import { ITestMessage } from 'vs/workbench/contrib/testing/common/testCollection';
export class TestingOutputPeekController implements IEditorContribution {
/**
* Gets the controller associated with the given code editor.
*/
public static get(editor: ICodeEditor): TestingOutputPeekController {
return editor.getContribution<TestingOutputPeekController>(Testing.OutputPeekContributionId);
}
/**
* Currently-shown peek view.
*/
private peek?: TestingOutputPeek;
constructor(private readonly editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService) { }
public dispose(): void {
// no-op
}
/**
* Shows a peek for the message in th editor.
*/
public show(output: ITestMessage) {
this.removePeek();
if (!output.location) {
return;
}
this.peek = this.instantiationService.createInstance(TestingOutputPeek, this.editor, output);
this.peek.show(output.location.range, 18);
}
private removePeek() {
if (this.peek) {
this.peek.dispose();
this.peek = undefined;
}
}
}
export class TestingOutputPeek extends PeekViewWidget {
private readonly disposable = new DisposableStore();
private diff?: EmbeddedDiffEditorWidget;
private dimension?: dom.Dimension;
constructor(
editor: ICodeEditor,
private readonly message: ITestMessage,
@IThemeService themeService: IThemeService,
@IPeekViewService peekViewService: IPeekViewService,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
@IUndoRedoService private readonly undoRedo: IUndoRedoService,
) {
super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true }, instantiationService);
this._disposables.add(themeService.onDidColorThemeChange(this.applyTheme, this));
this.applyTheme(themeService.getColorTheme());
peekViewService.addExclusiveWidget(editor, this);
this.create();
this.setTitle(message.message.toString());
}
private applyTheme(theme: IColorTheme) {
const borderColor = theme.getColor(peekViewBorder) || Color.transparent;
this.style({
arrowColor: borderColor,
frameColor: borderColor,
headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent,
primaryHeadingColor: theme.getColor(peekViewTitleForeground),
secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground)
});
}
/**
* @override
*/
public dispose() {
super.dispose();
this.disposable.dispose();
}
/**
* @override
*/
protected _fillBody(containerElement: HTMLElement): void {
const diffContainer = dom.append(containerElement, dom.$('div.preview.inline'));
let options: IDiffEditorOptions = {
scrollBeyondLastLine: false,
scrollbar: {
verticalScrollbarSize: 14,
horizontal: 'auto',
useShadows: true,
verticalHasArrows: false,
horizontalHasArrows: false,
alwaysConsumeMouseWheel: false
},
overviewRulerLanes: 2,
fixedOverflowWidgets: true,
readOnly: true,
minimap: {
enabled: false
},
enableSplitViewResizing: true,
isInEmbeddedEditor: true,
renderOverviewRuler: false,
ignoreTrimWhitespace: false,
renderSideBySide: true,
};
const preview = this.diff = this.instantiationService.createInstance(EmbeddedDiffEditorWidget, diffContainer, options, this.editor);
this.disposable.add(preview);
// todo: we probably want to have uri schemes for these guys since this
// does not work very well right now
preview.setModel(new SimpleDiffEditorModel(
new TextModel(this.message.expectedOutput!, TextModel.DEFAULT_CREATION_OPTIONS, null, null, this.undoRedo),
new TextModel(this.message.actualOutput!, TextModel.DEFAULT_CREATION_OPTIONS, null, null, this.undoRedo)
));
if (this.dimension) {
preview.layout(this.dimension);
}
}
/**
* @override
*/
protected _doLayoutBody(height: number, width: number) {
super._doLayoutBody(height, width);
this.dimension = new dom.Dimension(width, height);
this.diff?.layout(this.dimension);
}
}
class SimpleDiffEditorModel extends EditorModel {
constructor(
readonly original: TextModel,
readonly modified: TextModel,
) {
super();
}
async load(): Promise<this> {
return this;
}
}
......@@ -9,6 +9,7 @@ import { TestRunState } from 'vs/workbench/api/common/extHostTypes';
export const enum Testing {
ViewletId = 'workbench.view.testing',
ExplorerViewId = 'workbench.view.testing',
OutputPeekContributionId = 'editor.contrib.testingOutputPeek',
}
export const enum TestExplorerViewMode {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册