mirror of
https://github.com/Microsoft/vscode
synced 2024-10-30 01:37:20 +00:00
support Copy as HTML in the terminal (#144784)
This commit is contained in:
parent
5a751e2bed
commit
04f6cdc4ff
6 changed files with 73 additions and 5 deletions
|
@ -649,7 +649,7 @@ export interface ITerminalInstance {
|
||||||
/**
|
/**
|
||||||
* Copies the terminal selection to the clipboard.
|
* Copies the terminal selection to the clipboard.
|
||||||
*/
|
*/
|
||||||
copySelection(): Promise<void>;
|
copySelection(asHtml?: boolean): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current selection in the terminal.
|
* Current selection in the terminal.
|
||||||
|
|
|
@ -2113,6 +2113,20 @@ export function registerTerminalActions() {
|
||||||
await accessor.get(ITerminalService).activeInstance?.copySelection();
|
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) {
|
if (BrowserFeatures.clipboard.readText) {
|
||||||
|
|
|
@ -1126,10 +1126,21 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||||
return this.xterm ? this.xterm.raw.hasSelection() : false;
|
return this.xterm ? this.xterm.raw.hasSelection() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async copySelection(): Promise<void> {
|
async copySelection(asHtml?: boolean): Promise<void> {
|
||||||
const xterm = await this._xtermReadyPromise;
|
const xterm = await this._xtermReadyPromise;
|
||||||
if (this.hasSelection()) {
|
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 {
|
} else {
|
||||||
this._notificationService.warn(nls.localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy'));
|
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
|
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,
|
id: MenuId.TerminalInstanceContext,
|
||||||
item: {
|
item: {
|
||||||
|
@ -145,7 +156,7 @@ export function setupTerminalMenus(): void {
|
||||||
title: localize('workbench.action.terminal.paste.short', "Paste")
|
title: localize('workbench.action.terminal.paste.short', "Paste")
|
||||||
},
|
},
|
||||||
group: ContextMenuGroup.Edit,
|
group: ContextMenuGroup.Edit,
|
||||||
order: 2
|
order: 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -237,6 +248,17 @@ export function setupTerminalMenus(): void {
|
||||||
order: 1
|
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,
|
id: MenuId.TerminalEditorInstanceContext,
|
||||||
item: {
|
item: {
|
||||||
|
@ -245,7 +267,7 @@ export function setupTerminalMenus(): void {
|
||||||
title: localize('workbench.action.terminal.paste.short', "Paste")
|
title: localize('workbench.action.terminal.paste.short', "Paste")
|
||||||
},
|
},
|
||||||
group: ContextMenuGroup.Edit,
|
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 { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search';
|
||||||
import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11';
|
import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11';
|
||||||
import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl';
|
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 { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
|
||||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
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 SearchAddon: typeof SearchAddonType;
|
||||||
let Unicode11Addon: typeof Unicode11AddonType;
|
let Unicode11Addon: typeof Unicode11AddonType;
|
||||||
let WebglAddon: typeof WebglAddonType;
|
let WebglAddon: typeof WebglAddonType;
|
||||||
|
let SerializeAddon: typeof SerializeAddonType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the xterm object with additional functionality. Interaction with the backing process is out
|
* 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 _searchAddon?: SearchAddonType;
|
||||||
private _unicode11Addon?: Unicode11AddonType;
|
private _unicode11Addon?: Unicode11AddonType;
|
||||||
private _webglAddon?: WebglAddonType;
|
private _webglAddon?: WebglAddonType;
|
||||||
|
private _serializeAddon?: SerializeAddonType;
|
||||||
|
|
||||||
private readonly _onDidRequestRunCommand = new Emitter<string>();
|
private readonly _onDidRequestRunCommand = new Emitter<string>();
|
||||||
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
|
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
|
||||||
|
@ -167,6 +170,15 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
|
||||||
this.raw.loadAddon(this._decorationAddon);
|
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 {
|
attachToElement(container: HTMLElement): HTMLElement {
|
||||||
// Update the theme when attaching as the terminal location could have changed
|
// Update the theme when attaching as the terminal location could have changed
|
||||||
this._updateTheme();
|
this._updateTheme();
|
||||||
|
@ -404,6 +416,13 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
|
||||||
return WebglAddon;
|
return WebglAddon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async _getSerializeAddonConstructor(): Promise<typeof SerializeAddonType> {
|
||||||
|
if (!SerializeAddon) {
|
||||||
|
SerializeAddon = (await import('xterm-addon-serialize')).SerializeAddon;
|
||||||
|
}
|
||||||
|
return SerializeAddon;
|
||||||
|
}
|
||||||
|
|
||||||
private _disposeOfWebglRenderer(): void {
|
private _disposeOfWebglRenderer(): void {
|
||||||
try {
|
try {
|
||||||
this._webglAddon?.dispose();
|
this._webglAddon?.dispose();
|
||||||
|
|
|
@ -475,6 +475,7 @@ export const enum TerminalCommandId {
|
||||||
RunRecentCommand = 'workbench.action.terminal.runRecentCommand',
|
RunRecentCommand = 'workbench.action.terminal.runRecentCommand',
|
||||||
GoToRecentDirectory = 'workbench.action.terminal.goToRecentDirectory',
|
GoToRecentDirectory = 'workbench.action.terminal.goToRecentDirectory',
|
||||||
CopySelection = 'workbench.action.terminal.copySelection',
|
CopySelection = 'workbench.action.terminal.copySelection',
|
||||||
|
CopySelectionAsHtml = 'workbench.action.terminal.copySelectionAsHtml',
|
||||||
SelectAll = 'workbench.action.terminal.selectAll',
|
SelectAll = 'workbench.action.terminal.selectAll',
|
||||||
DeleteWordLeft = 'workbench.action.terminal.deleteWordLeft',
|
DeleteWordLeft = 'workbench.action.terminal.deleteWordLeft',
|
||||||
DeleteWordRight = 'workbench.action.terminal.deleteWordRight',
|
DeleteWordRight = 'workbench.action.terminal.deleteWordRight',
|
||||||
|
@ -566,6 +567,7 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
|
||||||
TerminalCommandId.ClearSelection,
|
TerminalCommandId.ClearSelection,
|
||||||
TerminalCommandId.Clear,
|
TerminalCommandId.Clear,
|
||||||
TerminalCommandId.CopySelection,
|
TerminalCommandId.CopySelection,
|
||||||
|
TerminalCommandId.CopySelectionAsHtml,
|
||||||
TerminalCommandId.DeleteToLineStart,
|
TerminalCommandId.DeleteToLineStart,
|
||||||
TerminalCommandId.DeleteWordLeft,
|
TerminalCommandId.DeleteWordLeft,
|
||||||
TerminalCommandId.DeleteWordRight,
|
TerminalCommandId.DeleteWordRight,
|
||||||
|
|
Loading…
Reference in a new issue