Xterm v3 integration (#2573)
This commit is contained in:
parent
5700690e0b
commit
dd780e6fe7
9 changed files with 310 additions and 2365 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -59,8 +59,13 @@ class TermGroup_ extends PureComponent {
|
|||
const props = getTermProps(uid, this.props, {
|
||||
isTermActive: uid === this.props.activeSession,
|
||||
term: termRef ? termRef.term : null,
|
||||
backgroundColor: this.props.backgroundColor,
|
||||
foregroundColor: this.props.foregroundColor,
|
||||
colors: this.props.colors,
|
||||
cursorBlink: this.props.cursorBlink,
|
||||
cursorShape: this.props.cursorShape,
|
||||
cursorColor: this.props.cursorColor,
|
||||
cursorAccentColor: this.props.cursorAccentColor,
|
||||
fontSize: this.props.fontSize,
|
||||
fontFamily: this.props.fontFamily,
|
||||
uiFontFamily: this.props.uiFontFamily,
|
||||
|
|
@ -81,6 +86,7 @@ class TermGroup_ extends PureComponent {
|
|||
onURLAbort: this.bind(this.props.onURLAbort, null, uid),
|
||||
onContextMenu: this.bind(this.props.onContextMenu, null, uid),
|
||||
borderColor: this.props.borderColor,
|
||||
selectionColor: this.props.selectionColor,
|
||||
quickEdit: this.props.quickEdit,
|
||||
uid
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
/* global Blob,URL,requestAnimationFrame */
|
||||
import React from 'react';
|
||||
import Terminal from 'xterm';
|
||||
import {Terminal} from 'xterm';
|
||||
import {clipboard} from 'electron';
|
||||
import * as Color from 'color';
|
||||
import {PureComponent} from '../base-components';
|
||||
import terms from '../terms';
|
||||
import processClipboard from '../utils/paste';
|
||||
|
|
@ -13,6 +14,41 @@ const CURSOR_STYLES = {
|
|||
BLOCK: 'block'
|
||||
};
|
||||
|
||||
const getTermOptions = props => {
|
||||
// Set a background color only if it is opaque
|
||||
const backgroundColor = Color(props.backgroundColor).alpha() < 1 ? 'transparent' : props.backgroundColor;
|
||||
return {
|
||||
cursorStyle: CURSOR_STYLES[props.cursorShape],
|
||||
cursorBlink: props.cursorBlink,
|
||||
fontFamily: props.fontFamily,
|
||||
fontSize: props.fontSize,
|
||||
allowTransparency: true,
|
||||
theme: {
|
||||
foreground: props.foregroundColor,
|
||||
background: backgroundColor,
|
||||
cursor: props.cursorColor,
|
||||
cursorAccent: props.cursorAccentColor,
|
||||
selection: props.selectionColor,
|
||||
black: props.colors.black,
|
||||
red: props.colors.red,
|
||||
green: props.colors.green,
|
||||
yellow: props.colors.yellow,
|
||||
blue: props.colors.blue,
|
||||
magenta: props.colors.magenta,
|
||||
cyan: props.colors.cyan,
|
||||
white: props.colors.white,
|
||||
brightBlack: props.colors.lightBlack,
|
||||
brightRed: props.colors.lightRed,
|
||||
brightGreen: props.colors.lightGreen,
|
||||
brightYellow: props.colors.lightYellow,
|
||||
brightBlue: props.colors.lightBlue,
|
||||
brightMagenta: props.colors.lightMagenta,
|
||||
brightCyan: props.colors.lightCyan,
|
||||
brightWhite: props.colors.lightWhite
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default class Term extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
@ -26,30 +62,23 @@ export default class Term extends PureComponent {
|
|||
this.onTermRef = this.onTermRef.bind(this);
|
||||
this.onTermWrapperRef = this.onTermWrapperRef.bind(this);
|
||||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
this.termOptions = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {props} = this;
|
||||
|
||||
// we need to use this hack to retain the term reference
|
||||
// as we move the term around splits, until xterm adds
|
||||
// support for getState / setState
|
||||
this.termOptions = getTermOptions(props);
|
||||
this.term = props.term || new Terminal(this.termOptions);
|
||||
this.term.attachCustomKeyEventHandler(this.keyboardHandler);
|
||||
this.term.open(this.termRef);
|
||||
if (props.term) {
|
||||
this.term = props.term;
|
||||
this.termRef.appendChild(this.term.element);
|
||||
this.onOpen();
|
||||
} else {
|
||||
this.term =
|
||||
props.term ||
|
||||
new Terminal({
|
||||
cursorStyle: CURSOR_STYLES[props.cursorShape],
|
||||
cursorBlink: props.cursorBlink
|
||||
});
|
||||
this.term.attachCustomKeyEventHandler(this.keyboardHandler);
|
||||
this.term.open(this.termRef);
|
||||
this.onOpen();
|
||||
//We need to set options again after reattaching an existing term
|
||||
Object.keys(this.termOptions).forEach(option => this.term.setOption(option, this.termOptions[option]));
|
||||
}
|
||||
|
||||
this.onOpen(this.termOptions);
|
||||
|
||||
if (props.onTitle) {
|
||||
this.term.on('title', props.onTitle);
|
||||
}
|
||||
|
|
@ -84,7 +113,7 @@ export default class Term extends PureComponent {
|
|||
terms[this.props.uid] = this;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
onOpen(termOptions) {
|
||||
// we need to delay one frame so that aphrodite styles
|
||||
// get applied and we can make an accurate measurement
|
||||
// of the container width and height
|
||||
|
|
@ -93,7 +122,9 @@ export default class Term extends PureComponent {
|
|||
// measurement to have taken place but it seems that
|
||||
// xterm.js might be doing this asynchronously, so
|
||||
// we force it instead
|
||||
this.term.charMeasure.measure();
|
||||
// eslint-disable-next-line no-debugger
|
||||
//debugger;
|
||||
this.term.charMeasure.measure(termOptions);
|
||||
this.fitResize();
|
||||
});
|
||||
}
|
||||
|
|
@ -179,10 +210,28 @@ export default class Term extends PureComponent {
|
|||
if (!this.props.cleared && nextProps.cleared) {
|
||||
this.clear();
|
||||
}
|
||||
const nextTermOptions = getTermOptions(nextProps);
|
||||
|
||||
// Update only options that have changed.
|
||||
Object.keys(nextTermOptions)
|
||||
.filter(option => option !== 'theme' && nextTermOptions[option] !== this.termOptions[option])
|
||||
.forEach(option => this.term.setOption(option, nextTermOptions[option]));
|
||||
|
||||
// Do we need to update theme?
|
||||
const shouldUpdateTheme =
|
||||
!this.termOptions.theme ||
|
||||
Object.keys(nextTermOptions.theme).some(option => {
|
||||
nextTermOptions.theme[option] !== this.termOptions.theme[option];
|
||||
});
|
||||
if (shouldUpdateTheme) {
|
||||
this.term.setOption('theme', nextTermOptions.theme);
|
||||
}
|
||||
|
||||
this.termOptions = nextTermOptions;
|
||||
|
||||
if (!this.props.isTermActive && nextProps.isTermActive) {
|
||||
requestAnimationFrame(() => {
|
||||
this.term.charMeasure.measure();
|
||||
this.term.charMeasure.measure(this.termOptions);
|
||||
this.fitResize();
|
||||
});
|
||||
}
|
||||
|
|
@ -190,7 +239,7 @@ export default class Term extends PureComponent {
|
|||
if (this.props.fontSize !== nextProps.fontSize || this.props.fontFamily !== nextProps.fontFamily) {
|
||||
// invalidate xterm cache about how wide each
|
||||
// character is
|
||||
this.term.charMeasure.measure();
|
||||
this.term.charMeasure.measure(this.termOptions);
|
||||
|
||||
// resize to fit the container
|
||||
this.fitResize();
|
||||
|
|
|
|||
|
|
@ -90,9 +90,13 @@ export default class Terms extends Component {
|
|||
activeSession: this.props.activeSession,
|
||||
sessions: this.props.sessions,
|
||||
backgroundColor: this.props.backgroundColor,
|
||||
foregroundColor: this.props.foregroundColor,
|
||||
borderColor: this.props.borderColor,
|
||||
selectionColor: this.props.selectionColor,
|
||||
colors: this.props.colors,
|
||||
cursorShape: this.props.cursorShape,
|
||||
cursorBlink: this.props.cursorBlink,
|
||||
cursorColor: this.props.cursorColor,
|
||||
fontSize: this.props.fontSize,
|
||||
fontFamily: this.props.fontFamily,
|
||||
uiFontFamily: this.props.uiFontFamily,
|
||||
|
|
@ -119,13 +123,9 @@ export default class Terms extends Component {
|
|||
})}
|
||||
{this.props.customChildren}
|
||||
<StyleSheet
|
||||
colors={this.props.colors}
|
||||
backgroundColor={this.props.backgroundColor}
|
||||
customCSS={this.props.customCSS}
|
||||
cursorColor={this.props.cursorColor}
|
||||
fontSize={this.props.fontSize}
|
||||
fontFamily={this.props.fontFamily}
|
||||
fontSmoothing={this.props.fontSmoothing}
|
||||
foregroundColor={this.props.foregroundColor}
|
||||
borderColor={this.props.borderColor}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -28,9 +28,11 @@ const TermsContainer = connect(
|
|||
fontSmoothing: state.ui.fontSmoothingOverride,
|
||||
padding: state.ui.padding,
|
||||
cursorColor: state.ui.cursorColor,
|
||||
cursorAccentColor: state.ui.cursorAccentColor,
|
||||
cursorShape: state.ui.cursorShape,
|
||||
cursorBlink: state.ui.cursorBlink,
|
||||
borderColor: state.ui.borderColor,
|
||||
selectionColor: state.ui.selectionColor,
|
||||
colors: state.ui.colors,
|
||||
foregroundColor: state.ui.foregroundColor,
|
||||
backgroundColor: state.ui.backgroundColor,
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@ const initial = Immutable({
|
|||
rows: null,
|
||||
activeUid: null,
|
||||
cursorColor: '#F81CE5',
|
||||
cursorAccentColor: '#000',
|
||||
cursorShape: 'BLOCK',
|
||||
cursorBlink: false,
|
||||
borderColor: '#333',
|
||||
selectionColor: 'rgba(248,28,229,0.3)',
|
||||
fontSize: 12,
|
||||
padding: '12px 14px',
|
||||
fontFamily: 'Menlo, "DejaVu Sans Mono", "Lucida Console", monospace',
|
||||
|
|
@ -131,6 +133,10 @@ const reducer = (state = initial, action) => {
|
|||
ret.cursorColor = config.cursorColor;
|
||||
}
|
||||
|
||||
if (config.cursorAccentColor) {
|
||||
ret.cursorAccentColor = config.cursorAccentColor;
|
||||
}
|
||||
|
||||
if (allowedCursorShapes.has(config.cursorShape)) {
|
||||
ret.cursorShape = config.cursorShape;
|
||||
}
|
||||
|
|
@ -143,6 +149,10 @@ const reducer = (state = initial, action) => {
|
|||
ret.borderColor = config.borderColor;
|
||||
}
|
||||
|
||||
if (config.selectionColor) {
|
||||
ret.selectionColor = config.selectionColor;
|
||||
}
|
||||
|
||||
if (typeof config.padding !== 'undefined' && config.padding !== null) {
|
||||
ret.padding = config.padding;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue