copy as html if possible (fixes #503)

This commit is contained in:
Eugene Pankov
2019-06-06 20:53:14 +02:00
parent 044a39abc9
commit 37a7d32bc8
3 changed files with 74 additions and 11 deletions

View File

@@ -5,6 +5,12 @@ import { enableLigatures } from 'xterm-addon-ligatures'
import { SearchAddon, ISearchOptions } from './xtermSearchAddon'
import './xterm.css'
import deepEqual = require('deep-equal')
import { Attributes, AttributeData, CellData } from 'xterm/src/core/buffer/BufferLine'
const COLOR_NAMES = [
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
'brightBlack', 'brightRed', 'brightGreen', 'brightYellow', 'brightBlue', 'brightMagenta', 'brightCyan', 'brightWhite'
]
/** @hidden */
export class XTermFrontend extends Frontend {
@@ -128,7 +134,10 @@ export class XTermFrontend extends Frontend {
}
copySelection (): void {
(navigator as any).clipboard.writeText(this.getSelection())
require('electron').remote.clipboard.write({
text: this.getSelection(),
html: this.getSelectionAsHTML()
})
}
clearSelection (): void {
@@ -189,13 +198,8 @@ export class XTermFrontend extends Frontend {
cursor: config.terminal.colorScheme.cursor,
}
const colorNames = [
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
'brightBlack', 'brightRed', 'brightGreen', 'brightYellow', 'brightBlue', 'brightMagenta', 'brightCyan', 'brightWhite'
]
for (let i = 0; i < colorNames.length; i++) {
theme[colorNames[i]] = config.terminal.colorScheme.colors[i]
for (let i = 0; i < COLOR_NAMES.length; i++) {
theme[COLOR_NAMES[i]] = config.terminal.colorScheme.colors[i]
}
if (this.xtermCore._colorManager && !deepEqual(this.configuredTheme, theme)) {
@@ -224,6 +228,59 @@ export class XTermFrontend extends Frontend {
private setFontSize () {
this.xterm.setOption('fontSize', this.configuredFontSize * Math.pow(1.1, this.zoom))
}
private getSelectionAsHTML (): string {
let html = `<div style="font-family: '${this.configService.store.terminal.font}', monospace; white-space: pre">`
const selection = this.xterm.getSelectionPosition()
if (!selection) {
return null
}
if (selection.startRow === selection.endRow) {
html += this.getLineAsHTML(selection.startRow, selection.startColumn, selection.endColumn)
} else {
html += this.getLineAsHTML(selection.startRow, selection.startColumn, this.xterm.cols)
for (let y = selection.startRow + 1; y < selection.endRow; y++) {
html += this.getLineAsHTML(y, 0, this.xterm.cols)
}
html += this.getLineAsHTML(selection.endRow, 0, selection.endColumn)
}
html += '</div>'
return html
}
private getHexColor (mode: number, color: number): string {
if (mode === Attributes.CM_RGB) {
let rgb = AttributeData.toColorRGB(color)
return rgb.map(x => x.toString(16).padStart(2, '0')).join('')
}
if (mode === Attributes.CM_P16 || mode === Attributes.CM_P256) {
return this.configService.store.terminal.colorScheme.colors[color]
}
return 'transparent'
}
private getLineAsHTML (y: number, start: number, end: number): string {
let html = '<div>'
let lastStyle = null
const line = (this.xterm.buffer.getLine(y) as any)._line
let cell = new CellData()
for (let i = start; i < end; i++) {
line.loadCell(i, cell)
const fg = this.getHexColor(cell.getFgColorMode(), cell.getFgColor())
const bg = this.getHexColor(cell.getBgColorMode(), cell.getBgColor())
const style = `color: ${fg}; background: ${bg}; font-weight: ${cell.isBold() ? 'bold' : 'normal'}; font-style: ${cell.isItalic() ? 'italic' : 'normal'}; text-decoration: ${cell.isUnderline() ? 'underline' : 'none'}`
if (style !== lastStyle) {
if (lastStyle !== null) {
html += '</span>'
}
html += `<span style="${style}">`
lastStyle = style
}
html += line.getString(i) || ' '
}
html += '</span></div>'
return html
}
}
/** @hidden */

View File

@@ -8,7 +8,10 @@
"declarationDir": "./typings",
"paths": {
"terminus-*": ["../../terminus-*"],
"*": ["../../app/node_modules/*"]
"*": [
"../../app/node_modules/*",
"../node_modules/xterm/src/*"
]
}
}
}

View File

@@ -18,7 +18,7 @@ module.exports = {
minimize: false,
},
resolve: {
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
modules: ['.', 'src', 'node_modules', '../app/node_modules', 'node_modules/xterm/src'].map(x => path.join(__dirname, x)),
extensions: ['.ts', '.js'],
},
module: {
@@ -32,7 +32,10 @@ module.exports = {
typeRoots: [path.resolve(__dirname, 'node_modules/@types')],
paths: {
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
"*": [path.resolve(__dirname, '../app/node_modules/*')],
"*": [
path.resolve(__dirname, '../app/node_modules/*'),
path.resolve(__dirname, './node_modules/xterm/src/*')
],
}
},
},