mirror of https://github.com/opensumi/core
fix: debugConsole context menus excute (#2394)
* fix: debug console context menus * fix: improve debug console output style * test: add debugConsole contextMenu test
This commit is contained in:
parent
75ac54e8fe
commit
62c02aafb0
|
@ -111,7 +111,7 @@
|
|||
"name": "Playwright Current File",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/tools/playwright/node_modules/.bin/playwright",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/playwright",
|
||||
"args": ["test", "--debug", "--config=./configs/playwright.debug.config.ts", "${fileBasenameNoExtension}"],
|
||||
"cwd": "${workspaceFolder}/tools/playwright",
|
||||
"console": "integratedTerminal",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
export const MARKER_CONTAINER_ID = 'markers';
|
||||
export const OUTPUT_CONTAINER_ID = 'output';
|
||||
export const TERMINAL_CONTAINER_ID = 'terminal';
|
||||
export const DEBUG_CONSOLE_CONTAINER_ID = 'debug-console-container';
|
||||
export const DEBUG_CONSOLE_CONTAINER_ID = 'debug-console';
|
||||
|
||||
// Left Panel 的 Container
|
||||
export const DEBUG_CONTAINER_ID = 'debug';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import throttle from 'lodash/throttle';
|
||||
|
||||
import { Autowired, Injectable, Optional } from '@opensumi/di';
|
||||
import { DisposableCollection, Emitter, Event, MessageType, ILogger } from '@opensumi/ide-core-common';
|
||||
import { DisposableCollection, Emitter, Event, MessageType, ILogger, localize } from '@opensumi/ide-core-common';
|
||||
import { IThemeService } from '@opensumi/ide-theme';
|
||||
import { DebugProtocol } from '@opensumi/vscode-debugprotocol/lib/debugProtocol';
|
||||
|
||||
|
@ -68,6 +68,8 @@ export class DebugConsoleSession implements IDebugConsoleSession {
|
|||
}
|
||||
|
||||
protected async logOutput(session: DebugSession, event: DebugProtocol.OutputEvent): Promise<void> {
|
||||
// [2J is the ansi escape sequence for clearing the display http://ascii-table.com/ansi-escape-sequences.php
|
||||
const clearAnsiSequence = '\u001b[2J';
|
||||
const body = event.body;
|
||||
const { category, variablesReference, source, line } = body;
|
||||
if (!this.treeModel) {
|
||||
|
@ -76,7 +78,9 @@ export class DebugConsoleSession implements IDebugConsoleSession {
|
|||
const severity =
|
||||
category === 'stderr'
|
||||
? MessageType.Error
|
||||
: event.body.category === 'console'
|
||||
: category === 'stdout'
|
||||
? MessageType.Info
|
||||
: category === 'console'
|
||||
? MessageType.Warning
|
||||
: MessageType.Info;
|
||||
if (category === 'telemetry') {
|
||||
|
@ -95,11 +99,23 @@ export class DebugConsoleSession implements IDebugConsoleSession {
|
|||
}
|
||||
}
|
||||
} else if (typeof body.output === 'string') {
|
||||
let output = body.output;
|
||||
if (output.indexOf(clearAnsiSequence) >= 0) {
|
||||
this.clearConsole();
|
||||
await this.insertItemWithAnsi(localize('debug.console.consoleCleare'), MessageType.Info);
|
||||
output = output.substring(output.lastIndexOf(clearAnsiSequence) + clearAnsiSequence.length);
|
||||
}
|
||||
const previousItem = this.getLastItem();
|
||||
/**
|
||||
* 如果上一条 output 结尾没有换行符则应该与下一条 output 拼接在一起
|
||||
* 如果上一次输出结尾没有换行符并且输出类型(MessageType)一致
|
||||
* 则将接下来的输出拼接至上一次输出后
|
||||
*/
|
||||
if (previousItem && !previousItem.description.endsWith('\n') && !previousItem.description.endsWith('\r\n')) {
|
||||
if (
|
||||
previousItem &&
|
||||
!previousItem.description.endsWith('\n') &&
|
||||
!previousItem.description.endsWith('\r\n') &&
|
||||
(previousItem as AnsiConsoleNode).severity === severity
|
||||
) {
|
||||
this.treeModel.root.unlinkItem(previousItem);
|
||||
await this.insertItemWithAnsi(previousItem.description + body.output, severity, source, line);
|
||||
} else {
|
||||
|
@ -110,6 +126,16 @@ export class DebugConsoleSession implements IDebugConsoleSession {
|
|||
this.fireDidChange();
|
||||
}
|
||||
|
||||
private async clearConsole() {
|
||||
const items = this.treeModel.root.flattenedBranch?.map((id) => this.treeModel.root.getTreeNodeById(id));
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
for (const item of items) {
|
||||
this.treeModel.root.unlinkItem(item as AnsiConsoleNode);
|
||||
}
|
||||
}
|
||||
|
||||
private async insertItemWithAnsi(
|
||||
output: string,
|
||||
severity?: MessageType,
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
} from '@opensumi/ide-core-browser';
|
||||
import { AbstractContextMenuService, MenuId, ICtxMenuRenderer } from '@opensumi/ide-core-browser/lib/menu/next';
|
||||
|
||||
import { IDebugSessionManager } from '../../../common';
|
||||
import { IDebugConsoleModelService, IDebugSessionManager } from '../../../common';
|
||||
import { LinkDetector } from '../../debug-link-detector';
|
||||
import { DebugSession } from '../../debug-session';
|
||||
import { DidChangeActiveDebugSession } from '../../debug-session-manager';
|
||||
|
@ -50,7 +50,7 @@ export interface IDebugConsoleModel {
|
|||
}
|
||||
|
||||
@Injectable()
|
||||
export class DebugConsoleModelService {
|
||||
export class DebugConsoleModelService implements IDebugConsoleModelService {
|
||||
private static DEFAULT_REFRESH_DELAY = 200;
|
||||
|
||||
@Autowired(INJECTOR_TOKEN)
|
||||
|
@ -164,16 +164,16 @@ export class DebugConsoleModelService {
|
|||
return this.onDidRefreshedEmitter.event;
|
||||
}
|
||||
|
||||
clear = () => {
|
||||
clear() {
|
||||
// 重新初始化Console中渲染的TreeModel
|
||||
this.initTreeModel(this.manager.currentSession, true);
|
||||
};
|
||||
}
|
||||
|
||||
collapseAll = () => {
|
||||
collapseAll() {
|
||||
this.treeModel?.root.collapsedAll();
|
||||
};
|
||||
}
|
||||
|
||||
copyAll = () => {
|
||||
copyAll() {
|
||||
let text = '';
|
||||
if (!this.treeModel?.root || !this.treeModel.root.children) {
|
||||
return;
|
||||
|
@ -182,15 +182,18 @@ export class DebugConsoleModelService {
|
|||
text += this.getValidText(child as DebugConsoleNode) + '\n';
|
||||
}
|
||||
this.clipboardService.writeText(text.slice(0, -'\n'.length));
|
||||
};
|
||||
}
|
||||
|
||||
copy = (node: DebugConsoleNode) => {
|
||||
copy(node: DebugConsoleNode) {
|
||||
if (node) {
|
||||
this.clipboardService.writeText(this.getValidText(node));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private getValidText(node: DebugConsoleNode) {
|
||||
if (node.description.endsWith('\n')) {
|
||||
return node.description.slice(0, -'\n'.length);
|
||||
}
|
||||
return node.description;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
IDebugSessionManager,
|
||||
CONTEXT_IN_DEBUG_MODE_KEY,
|
||||
DebugState,
|
||||
IDebugConsoleModelService,
|
||||
} from '../../../common';
|
||||
import { DebugSessionManager } from '../../debug-session-manager';
|
||||
|
||||
|
@ -47,7 +48,7 @@ const consoleInputMonacoOptions: monaco.editor.IEditorOptions = {
|
|||
|
||||
@Injectable()
|
||||
export class DebugConsoleService implements IHistoryNavigationWidget {
|
||||
@Autowired(DebugConsoleModelService)
|
||||
@Autowired(IDebugConsoleModelService)
|
||||
protected readonly debugConsoleModelService: DebugConsoleModelService;
|
||||
|
||||
@Autowired(IMainLayoutService)
|
||||
|
@ -115,7 +116,7 @@ export class DebugConsoleService implements IHistoryNavigationWidget {
|
|||
return bottomPanelHandler && bottomPanelHandler.isVisible;
|
||||
}
|
||||
|
||||
public get consoleModel(): DebugConsoleModelService {
|
||||
public get consoleModel() {
|
||||
return this.debugConsoleModelService;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,10 @@ export interface IDebugConsoleSession extends ITree {
|
|||
}
|
||||
|
||||
export interface IDebugConsoleModelService {
|
||||
debugConsoleSession: IDebugConsoleSession;
|
||||
debugConsoleSession?: IDebugConsoleSession;
|
||||
clear(): void;
|
||||
copyAll(): void;
|
||||
collapseAll(): void;
|
||||
copy(node: ITreeNode): void;
|
||||
execute(value: string): Promise<void>;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import { DebugConfigurationManager } from '@opensumi/ide-debug/lib/browser/debug
|
|||
import { DebugPreferences } from '@opensumi/ide-debug/lib/browser/debug-preferences';
|
||||
import { DebugSessionContributionRegistry } from '@opensumi/ide-debug/lib/browser/debug-session-contribution';
|
||||
import { DebugSessionManager } from '@opensumi/ide-debug/lib/browser/debug-session-manager';
|
||||
import { DebugConsoleModelService } from '@opensumi/ide-debug/lib/browser/view/console/debug-console-tree.model.service';
|
||||
import { IDebugService, IDebugServer } from '@opensumi/ide-debug/lib/common/debug-service';
|
||||
import { IDebugSessionManager, IDebugSessionOptions } from '@opensumi/ide-debug/lib/common/debug-session';
|
||||
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
||||
|
@ -98,7 +99,7 @@ export class MainThreadDebug implements IMainThreadDebug {
|
|||
protected readonly terminalService: ITerminalApiService;
|
||||
|
||||
@Autowired(IDebugConsoleModelService)
|
||||
protected readonly debugConsoleModelService: IDebugConsoleModelService;
|
||||
protected readonly debugConsoleModelService: DebugConsoleModelService;
|
||||
|
||||
@Autowired(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
|
|
@ -309,6 +309,7 @@ export const localizationBundle = {
|
|||
'debug.console.followLink': '{0} + click to follow link',
|
||||
'debug.console.input.placeholder': 'Please start a debug session to evaluate expressions',
|
||||
'debug.console.errorMessage': 'Debug session initialization failed. See console for details.',
|
||||
'debug.console.consoleCleared': 'Console was cleared',
|
||||
'debug.notSupported.type': 'Debug type "{0}" is not supported, please check your launch config.',
|
||||
'debug.notSupported.any': 'Debug is not supported, please check your launch config.',
|
||||
|
||||
|
|
|
@ -269,6 +269,7 @@ export const localizationBundle = {
|
|||
'debug.console.followLink': '按住 {0} 并单击可访问链接',
|
||||
'debug.console.errorMessage': '调试进程初始化异常,请打开控制面板查看错误日志',
|
||||
'debug.console.input.placeholder': '请发起调试会话来对表达式求值',
|
||||
'debug.console.consoleCleared': '输出已清理',
|
||||
'debug.notSupported.type': '调试类型 "{0}" 不是支持的调试类型,请检查配置或安装对应调试插件',
|
||||
'debug.notSupported.any': '当前调试配置不支持,请检查配置或安装对应调试插件',
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { OpenSumiApp } from './app';
|
||||
import { OpenSumiContextMenu } from './context-menu';
|
||||
import { OpenSumiPanel } from './panel';
|
||||
|
||||
export class OpenSumiDebugConsoleView extends OpenSumiPanel {
|
||||
constructor(app: OpenSumiApp) {
|
||||
super(app, 'DEBUG-CONSOLE');
|
||||
}
|
||||
|
||||
async getOutputContainer() {
|
||||
return this.view?.$('[class*="debug_console_output__"]');
|
||||
}
|
||||
|
||||
async openConsoleContextMenu() {
|
||||
const view = await this.getOutputContainer();
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
return OpenSumiContextMenu.open(this.app, async () => view);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import path from 'path';
|
|||
import { expect } from '@playwright/test';
|
||||
|
||||
import { OpenSumiApp } from '../app';
|
||||
import { OpenSumiDebugConsoleView } from '../debug-console-view';
|
||||
import { OpenSumiDebugView } from '../debug-view';
|
||||
import { OpenSumiExplorerView } from '../explorer-view';
|
||||
import { OpenSumiTerminalView } from '../terminal-view';
|
||||
|
@ -80,6 +81,41 @@ test.describe('OpenSumi Debug', () => {
|
|||
await page.waitForTimeout(1000);
|
||||
});
|
||||
|
||||
test('ContextMenu on DebugConsole should be work', async () => {
|
||||
editor = await app.openEditor(OpenSumiTextEditor, explorer, 'index.js', false);
|
||||
await app.page.waitForTimeout(1000);
|
||||
|
||||
debugView = await app.open(OpenSumiDebugView);
|
||||
const glyphMarginModel = await editor.getGlyphMarginModel();
|
||||
const glyphOverlay = await glyphMarginModel.getOverlay(6);
|
||||
expect(glyphOverlay).toBeDefined();
|
||||
if (!glyphOverlay) {
|
||||
return;
|
||||
}
|
||||
const isClicked = await glyphMarginModel.hasBreakpoint(glyphOverlay);
|
||||
if (!isClicked) {
|
||||
await glyphOverlay?.click({ position: { x: 9, y: 9 }, force: true });
|
||||
await app.page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
await debugView.start();
|
||||
await app.page.waitForTimeout(2000);
|
||||
|
||||
const debugConsole = await app.open(OpenSumiDebugConsoleView);
|
||||
const contextMenu = await debugConsole.openConsoleContextMenu();
|
||||
await app.page.waitForTimeout(200);
|
||||
expect(await contextMenu?.isOpen()).toBeTruthy();
|
||||
const copyAll = await contextMenu?.menuItemByName('Copy All');
|
||||
await copyAll?.click();
|
||||
await app.page.waitForTimeout(1000);
|
||||
const text = (await page.evaluate('navigator.clipboard.readText()')) as string;
|
||||
expect(text.includes('Debugger attached.')).toBeTruthy();
|
||||
|
||||
await editor.close();
|
||||
await debugView.stop();
|
||||
await page.waitForTimeout(1000);
|
||||
});
|
||||
|
||||
test('Run Debug by Javascript Debug Terminal', async () => {
|
||||
await explorer.open();
|
||||
editor = await app.openEditor(OpenSumiTextEditor, explorer, 'index.js', false);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceFolder}/index.js",
|
||||
"outputCapture": "std",
|
||||
"skipFiles": ["<node_internals>/**"]
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue