mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
support Copy as HTML in the terminal (#144784)
This commit is contained in:
parent
5a751e2bed
commit
04f6cdc4ff
|
@ -649,7 +649,7 @@ export interface ITerminalInstance {
|
|||
/**
|
||||
* Copies the terminal selection to the clipboard.
|
||||
*/
|
||||
copySelection(): Promise<void>;
|
||||
copySelection(asHtml?: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Current selection in the terminal.
|
||||
|
|
|
@ -2113,6 +2113,20 @@ export function registerTerminalActions() {
|
|||
await accessor.get(ITerminalService).activeInstance?.copySelection();
|
||||
}
|
||||
});
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: TerminalCommandId.CopySelectionAsHtml,
|
||||
title: { value: localize('workbench.action.terminal.copySelectionAsHtml', "Copy Selection as HTML"), original: 'Copy Selection as HTML' },
|
||||
f1: true,
|
||||
category,
|
||||
precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected)
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor) {
|
||||
await accessor.get(ITerminalService).activeInstance?.copySelection(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (BrowserFeatures.clipboard.readText) {
|
||||
|
|
|
@ -1126,10 +1126,21 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
return this.xterm ? this.xterm.raw.hasSelection() : false;
|
||||
}
|
||||
|
||||
async copySelection(): Promise<void> {
|
||||
async copySelection(asHtml?: boolean): Promise<void> {
|
||||
const xterm = await this._xtermReadyPromise;
|
||||
if (this.hasSelection()) {
|
||||
await this._clipboardService.writeText(xterm.raw.getSelection());
|
||||
if (asHtml) {
|
||||
const selectionAsHtml = await xterm.getSelectionAsHtml();
|
||||
function listener(e: any) {
|
||||
e.clipboardData.setData('text/html', selectionAsHtml);
|
||||
e.preventDefault();
|
||||
}
|
||||
document.addEventListener('copy', listener);
|
||||
document.execCommand('copy');
|
||||
document.removeEventListener('copy', listener);
|
||||
} else {
|
||||
await this._clipboardService.writeText(xterm.raw.getSelection());
|
||||
}
|
||||
} else {
|
||||
this._notificationService.warn(nls.localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy'));
|
||||
}
|
||||
|
|
|
@ -137,6 +137,17 @@ export function setupTerminalMenus(): void {
|
|||
order: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
id: MenuId.TerminalInstanceContext,
|
||||
item: {
|
||||
command: {
|
||||
id: TerminalCommandId.CopySelectionAsHtml,
|
||||
title: localize('workbench.action.terminal.copySelectionAsHtml', "Copy as HTML")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
id: MenuId.TerminalInstanceContext,
|
||||
item: {
|
||||
|
@ -145,7 +156,7 @@ export function setupTerminalMenus(): void {
|
|||
title: localize('workbench.action.terminal.paste.short', "Paste")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 2
|
||||
order: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -237,6 +248,17 @@ export function setupTerminalMenus(): void {
|
|||
order: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
id: MenuId.TerminalEditorInstanceContext,
|
||||
item: {
|
||||
command: {
|
||||
id: TerminalCommandId.CopySelectionAsHtml,
|
||||
title: localize('workbench.action.terminal.copySelectionAsHtml', "Copy as HTML")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
id: MenuId.TerminalEditorInstanceContext,
|
||||
item: {
|
||||
|
@ -245,7 +267,7 @@ export function setupTerminalMenus(): void {
|
|||
title: localize('workbench.action.terminal.paste.short', "Paste")
|
||||
},
|
||||
group: ContextMenuGroup.Edit,
|
||||
order: 2
|
||||
order: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ import type { IBuffer, ITheme, RendererType, Terminal as RawXtermTerminal } from
|
|||
import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search';
|
||||
import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11';
|
||||
import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl';
|
||||
import { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize';
|
||||
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
|
@ -42,6 +43,7 @@ const NUMBER_OF_FRAMES_TO_MEASURE = 20;
|
|||
let SearchAddon: typeof SearchAddonType;
|
||||
let Unicode11Addon: typeof Unicode11AddonType;
|
||||
let WebglAddon: typeof WebglAddonType;
|
||||
let SerializeAddon: typeof SerializeAddonType;
|
||||
|
||||
/**
|
||||
* Wraps the xterm object with additional functionality. Interaction with the backing process is out
|
||||
|
@ -64,6 +66,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
|
|||
private _searchAddon?: SearchAddonType;
|
||||
private _unicode11Addon?: Unicode11AddonType;
|
||||
private _webglAddon?: WebglAddonType;
|
||||
private _serializeAddon?: SerializeAddonType;
|
||||
|
||||
private readonly _onDidRequestRunCommand = new Emitter<string>();
|
||||
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
|
||||
|
@ -167,6 +170,15 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
|
|||
this.raw.loadAddon(this._decorationAddon);
|
||||
}
|
||||
|
||||
async getSelectionAsHtml(): Promise<string> {
|
||||
if (!this._serializeAddon) {
|
||||
const Addon = await this._getSerializeAddonConstructor();
|
||||
this._serializeAddon = new Addon();
|
||||
this.raw.loadAddon(this._serializeAddon);
|
||||
}
|
||||
return this._serializeAddon.serializeAsHTML({ onlySelection: true });
|
||||
}
|
||||
|
||||
attachToElement(container: HTMLElement): HTMLElement {
|
||||
// Update the theme when attaching as the terminal location could have changed
|
||||
this._updateTheme();
|
||||
|
@ -404,6 +416,13 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
|
|||
return WebglAddon;
|
||||
}
|
||||
|
||||
protected async _getSerializeAddonConstructor(): Promise<typeof SerializeAddonType> {
|
||||
if (!SerializeAddon) {
|
||||
SerializeAddon = (await import('xterm-addon-serialize')).SerializeAddon;
|
||||
}
|
||||
return SerializeAddon;
|
||||
}
|
||||
|
||||
private _disposeOfWebglRenderer(): void {
|
||||
try {
|
||||
this._webglAddon?.dispose();
|
||||
|
|
|
@ -475,6 +475,7 @@ export const enum TerminalCommandId {
|
|||
RunRecentCommand = 'workbench.action.terminal.runRecentCommand',
|
||||
GoToRecentDirectory = 'workbench.action.terminal.goToRecentDirectory',
|
||||
CopySelection = 'workbench.action.terminal.copySelection',
|
||||
CopySelectionAsHtml = 'workbench.action.terminal.copySelectionAsHtml',
|
||||
SelectAll = 'workbench.action.terminal.selectAll',
|
||||
DeleteWordLeft = 'workbench.action.terminal.deleteWordLeft',
|
||||
DeleteWordRight = 'workbench.action.terminal.deleteWordRight',
|
||||
|
@ -566,6 +567,7 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
|
|||
TerminalCommandId.ClearSelection,
|
||||
TerminalCommandId.Clear,
|
||||
TerminalCommandId.CopySelection,
|
||||
TerminalCommandId.CopySelectionAsHtml,
|
||||
TerminalCommandId.DeleteToLineStart,
|
||||
TerminalCommandId.DeleteWordLeft,
|
||||
TerminalCommandId.DeleteWordRight,
|
||||
|
|
Loading…
Reference in a new issue