hyper/lib/components/term.js

230 lines
5.2 KiB
JavaScript
Raw Normal View History

2016-07-14 15:40:15 -08:00
/* global Blob,URL,requestAnimationFrame */
2016-07-13 12:44:24 -08:00
import React from 'react';
import Component from '../component';
import terms from '../terms';
2017-06-11 02:42:39 -08:00
import Terminal from 'hyper-xterm-tmp';
// map old hterm constants to xterm.js
const CURSOR_STYLES = {
BEAM: 'bar',
UNDERLINE: 'underline',
BLOCK: 'block'
}
2016-06-30 22:01:04 -08:00
export default class Term extends Component {
constructor(props) {
2016-07-13 12:44:24 -08:00
super(props);
props.ref_(this);
2017-06-11 02:42:39 -08:00
this.termRef = null
2017-08-02 11:05:47 -08:00
this.termWrapperRef = null
this.termRect = null
this.onOpen = this.onOpen.bind(this)
2017-06-11 02:42:39 -08:00
this.onWindowResize = this.onWindowResize.bind(this)
2016-07-13 12:44:24 -08:00
}
componentDidMount() {
const {props} = this;
2016-06-30 22:01:04 -08:00
2017-08-02 11:05:47 -08:00
// 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
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.on('open', this.onOpen)
this.term.open(this.termRef, {
focus: false
})
}
2017-06-11 02:42:39 -08:00
if (props.onTitle) {
this.term.on(
'title',
props.onTitle
)
}
2016-07-03 12:35:45 -08:00
2017-06-11 02:42:39 -08:00
if (props.onActive) {
this.term.on(
'focus',
2017-08-02 11:05:47 -08:00
props.onActive
2017-06-11 02:42:39 -08:00
)
}
2017-06-11 02:42:39 -08:00
if (props.onData) {
this.term.on(
'data',
props.onData
)
}
2017-06-11 02:42:39 -08:00
if (props.onResize) {
this.term.on(
'resize',
({ cols, rows }) => {
props.onResize(cols, rows)
2016-07-13 12:44:24 -08:00
}
2017-06-11 02:42:39 -08:00
)
}
2016-07-13 12:44:24 -08:00
2017-08-02 11:05:47 -08:00
window.addEventListener('resize', this.onWindowResize, {
passive: true
})
Split Panes (#693) * npm: add .npmrc with save-exact=true * split panes: create initial implementation This allows users to split their Hyperterm terms into multiple nested splits, both vertical and horizontal. Fixes #56 * split panes: suport closing tabs and individual panes * split panes: ensure new splits are placed at the correct index New split panes should be placed after the currently active pane, not at the end like they were previously. * split panes: add explicit dependency to uuid * split panes: implement split pane cycling This adds menu buttons for moving back and forward between open split panes in the currect terminal tab. Doesn't add a hotkey yet, needs some bikeshedding. * split panes: move activeSessionUid to its own object It made little sense to have so many objects with `activeSessionUid` set to `null` when it only mattered on the top level. Now it's an object mapping term-group `uid` to `sessionUid` instead. * split panes: make sure closing the last split pane exits the app * split panes: fix a crash after closing specific panes Sometimes the terminal would crash when a specific split pane was closed, because the `activeSessions` mapping wasn't updated correctly. * split panes: fix a bug that caused initial session sizing to be wrong * fix all our focus / blur issues in one fell swoop :O (famous last words) * get rid of react warning * hterm: make sure not to lose focus when VT listens on clicks * term: restore onactive callback * add missing `return` to override (just in case) * split pane: new split pane implementation * goodbye react-split-pane * added term group resizing action and reducer * terms: supply border color so that we can use it for splits * term-group: add resizing hook * term-groups: add resizing constant * remove split pane css side-effect * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split-pane: remove `console.log` * split-pane: remove `console.log` * split panes: rebalance sizes on insert/removal * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split panes: rebalance sizes on insert/removal * split panes: set a minimum size for resizing * split-pane: fix vertical splits * css :| * package: bump electron * split panes: attach onFocus listener to webviews * 1.4.1 and 1.4.2 are broken. they have the following regression: - open google.com on the main window - open a new tab - come back to previous tab. webview is gone :| * split panes: handle PTY exits * split panes: add linux friendly keybindings
2016-10-03 18:00:50 -08:00
terms[this.props.uid] = this;
2016-07-13 12:44:24 -08:00
}
2017-08-02 11:05:47 -08:00
onOpen () {
// 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
requestAnimationFrame(() => {
// at this point it would make sense for character
// 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();
this.measureResize();
})
}
2017-06-11 02:42:39 -08:00
getTermDocument () {
// eslint-disable-next-line no-console
console.error('unimplemented')
}
2017-08-02 11:05:47 -08:00
// measures the container and makes the decision
// whether to resize the term to fit the container
measureResize () {
console.log('performing measure resize')
const termRect = this.termWrapperRef.getBoundingClientRect()
if (!this.termRect ||
termRect.width !== this.termRect.width ||
termRect.height !== this.termRect.height) {
this.termRect = termRect;
console.log('performing fit resize')
this.fitResize()
}
}
2017-06-11 02:42:39 -08:00
onWindowResize() {
2017-08-02 11:05:47 -08:00
this.measureResize();
Split Panes (#693) * npm: add .npmrc with save-exact=true * split panes: create initial implementation This allows users to split their Hyperterm terms into multiple nested splits, both vertical and horizontal. Fixes #56 * split panes: suport closing tabs and individual panes * split panes: ensure new splits are placed at the correct index New split panes should be placed after the currently active pane, not at the end like they were previously. * split panes: add explicit dependency to uuid * split panes: implement split pane cycling This adds menu buttons for moving back and forward between open split panes in the currect terminal tab. Doesn't add a hotkey yet, needs some bikeshedding. * split panes: move activeSessionUid to its own object It made little sense to have so many objects with `activeSessionUid` set to `null` when it only mattered on the top level. Now it's an object mapping term-group `uid` to `sessionUid` instead. * split panes: make sure closing the last split pane exits the app * split panes: fix a crash after closing specific panes Sometimes the terminal would crash when a specific split pane was closed, because the `activeSessions` mapping wasn't updated correctly. * split panes: fix a bug that caused initial session sizing to be wrong * fix all our focus / blur issues in one fell swoop :O (famous last words) * get rid of react warning * hterm: make sure not to lose focus when VT listens on clicks * term: restore onactive callback * add missing `return` to override (just in case) * split pane: new split pane implementation * goodbye react-split-pane * added term group resizing action and reducer * terms: supply border color so that we can use it for splits * term-group: add resizing hook * term-groups: add resizing constant * remove split pane css side-effect * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split-pane: remove `console.log` * split-pane: remove `console.log` * split panes: rebalance sizes on insert/removal * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split panes: rebalance sizes on insert/removal * split panes: set a minimum size for resizing * split-pane: fix vertical splits * css :| * package: bump electron * split panes: attach onFocus listener to webviews * 1.4.1 and 1.4.2 are broken. they have the following regression: - open google.com on the main window - open a new tab - come back to previous tab. webview is gone :| * split panes: handle PTY exits * split panes: add linux friendly keybindings
2016-10-03 18:00:50 -08:00
}
write(data) {
2017-06-11 02:42:39 -08:00
this.term.write(data);
2016-07-13 12:44:24 -08:00
}
focus() {
2017-06-11 02:42:39 -08:00
this.term.focus();
2016-07-13 12:44:24 -08:00
}
clear() {
2017-06-11 02:42:39 -08:00
this.term.clear();
2017-08-02 11:05:47 -08:00
}
reset () {
this.term.reset();
}
resize (cols, rows) {
this.term.resize(cols, rows);
}
fitResize () {
const cols = Math.floor(
this.termRect.width / this.term.charMeasure.width
)
const rows = Math.floor(
this.termRect.height / this.term.charMeasure.height
)
if (cols !== this.props.cols || rows !== this.props.rows) {
this.resize(cols, rows)
}
2016-07-03 12:35:45 -08:00
}
componentWillReceiveProps(nextProps) {
2016-07-13 12:44:24 -08:00
if (!this.props.cleared && nextProps.cleared) {
this.clear();
2016-07-05 12:14:30 -08:00
}
2017-08-02 11:05:47 -08:00
if (this.props.fontSize !== nextProps.fontSize ||
this.props.fontFamily !== nextProps.fontFamily) {
// invalidate xterm cache about how wide each
// character is
this.term.charMeasure.measure()
// resize to fit the container
this.fitResize()
}
if (nextProps.rows !== this.props.rows ||
nextProps.cols !== this.props.cols) {
this.resize(nextProps.cols, nextProps.rows)
}
2016-06-30 22:01:04 -08:00
}
componentWillUnmount() {
terms[this.props.uid] = this;
2016-07-13 12:44:24 -08:00
this.props.ref_(null);
2017-08-02 11:05:47 -08:00
// to clean up the terminal, we remove the listeners
// instead of invoking `destroy`, since it will make the
// term insta un-attachable in the future (which we need
// to do in case of splitting, see `componentDidMount`
this.term._events = {}
window.removeEventListener('resize', this.onWindowResize, {
passive: true
})
2016-06-30 22:01:04 -08:00
}
template(css) {
Split Panes (#693) * npm: add .npmrc with save-exact=true * split panes: create initial implementation This allows users to split their Hyperterm terms into multiple nested splits, both vertical and horizontal. Fixes #56 * split panes: suport closing tabs and individual panes * split panes: ensure new splits are placed at the correct index New split panes should be placed after the currently active pane, not at the end like they were previously. * split panes: add explicit dependency to uuid * split panes: implement split pane cycling This adds menu buttons for moving back and forward between open split panes in the currect terminal tab. Doesn't add a hotkey yet, needs some bikeshedding. * split panes: move activeSessionUid to its own object It made little sense to have so many objects with `activeSessionUid` set to `null` when it only mattered on the top level. Now it's an object mapping term-group `uid` to `sessionUid` instead. * split panes: make sure closing the last split pane exits the app * split panes: fix a crash after closing specific panes Sometimes the terminal would crash when a specific split pane was closed, because the `activeSessions` mapping wasn't updated correctly. * split panes: fix a bug that caused initial session sizing to be wrong * fix all our focus / blur issues in one fell swoop :O (famous last words) * get rid of react warning * hterm: make sure not to lose focus when VT listens on clicks * term: restore onactive callback * add missing `return` to override (just in case) * split pane: new split pane implementation * goodbye react-split-pane * added term group resizing action and reducer * terms: supply border color so that we can use it for splits * term-group: add resizing hook * term-groups: add resizing constant * remove split pane css side-effect * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split-pane: remove `console.log` * split-pane: remove `console.log` * split panes: rebalance sizes on insert/removal * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split panes: rebalance sizes on insert/removal * split panes: set a minimum size for resizing * split-pane: fix vertical splits * css :| * package: bump electron * split panes: attach onFocus listener to webviews * 1.4.1 and 1.4.2 are broken. they have the following regression: - open google.com on the main window - open a new tab - come back to previous tab. webview is gone :| * split panes: handle PTY exits * split panes: add linux friendly keybindings
2016-10-03 18:00:50 -08:00
return (<div
className={css('fit', this.props.isTermActive && 'active')}
Split Panes (#693) * npm: add .npmrc with save-exact=true * split panes: create initial implementation This allows users to split their Hyperterm terms into multiple nested splits, both vertical and horizontal. Fixes #56 * split panes: suport closing tabs and individual panes * split panes: ensure new splits are placed at the correct index New split panes should be placed after the currently active pane, not at the end like they were previously. * split panes: add explicit dependency to uuid * split panes: implement split pane cycling This adds menu buttons for moving back and forward between open split panes in the currect terminal tab. Doesn't add a hotkey yet, needs some bikeshedding. * split panes: move activeSessionUid to its own object It made little sense to have so many objects with `activeSessionUid` set to `null` when it only mattered on the top level. Now it's an object mapping term-group `uid` to `sessionUid` instead. * split panes: make sure closing the last split pane exits the app * split panes: fix a crash after closing specific panes Sometimes the terminal would crash when a specific split pane was closed, because the `activeSessions` mapping wasn't updated correctly. * split panes: fix a bug that caused initial session sizing to be wrong * fix all our focus / blur issues in one fell swoop :O (famous last words) * get rid of react warning * hterm: make sure not to lose focus when VT listens on clicks * term: restore onactive callback * add missing `return` to override (just in case) * split pane: new split pane implementation * goodbye react-split-pane * added term group resizing action and reducer * terms: supply border color so that we can use it for splits * term-group: add resizing hook * term-groups: add resizing constant * remove split pane css side-effect * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split-pane: remove `console.log` * split-pane: remove `console.log` * split panes: rebalance sizes on insert/removal * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split panes: rebalance sizes on insert/removal * split panes: set a minimum size for resizing * split-pane: fix vertical splits * css :| * package: bump electron * split panes: attach onFocus listener to webviews * 1.4.1 and 1.4.2 are broken. they have the following regression: - open google.com on the main window - open a new tab - come back to previous tab. webview is gone :| * split panes: handle PTY exits * split panes: add linux friendly keybindings
2016-10-03 18:00:50 -08:00
style={{padding: this.props.padding}}
>
2016-07-13 12:44:24 -08:00
{ this.props.customChildrenBefore }
<div
ref={component => {
2017-08-02 11:05:47 -08:00
this.termWrapperRef = component;
}}
2017-08-02 11:05:47 -08:00
className={css('fit', 'wrapper')}
>
<div
ref={component => {
this.termRef = component;
}}
className={css('term')}
/>
</div>
2016-07-13 12:44:24 -08:00
{ this.props.customChildren }
</div>);
2016-06-30 22:01:04 -08:00
}
styles() {
2016-07-13 12:44:24 -08:00
return {
fit: {
Split Panes (#693) * npm: add .npmrc with save-exact=true * split panes: create initial implementation This allows users to split their Hyperterm terms into multiple nested splits, both vertical and horizontal. Fixes #56 * split panes: suport closing tabs and individual panes * split panes: ensure new splits are placed at the correct index New split panes should be placed after the currently active pane, not at the end like they were previously. * split panes: add explicit dependency to uuid * split panes: implement split pane cycling This adds menu buttons for moving back and forward between open split panes in the currect terminal tab. Doesn't add a hotkey yet, needs some bikeshedding. * split panes: move activeSessionUid to its own object It made little sense to have so many objects with `activeSessionUid` set to `null` when it only mattered on the top level. Now it's an object mapping term-group `uid` to `sessionUid` instead. * split panes: make sure closing the last split pane exits the app * split panes: fix a crash after closing specific panes Sometimes the terminal would crash when a specific split pane was closed, because the `activeSessions` mapping wasn't updated correctly. * split panes: fix a bug that caused initial session sizing to be wrong * fix all our focus / blur issues in one fell swoop :O (famous last words) * get rid of react warning * hterm: make sure not to lose focus when VT listens on clicks * term: restore onactive callback * add missing `return` to override (just in case) * split pane: new split pane implementation * goodbye react-split-pane * added term group resizing action and reducer * terms: supply border color so that we can use it for splits * term-group: add resizing hook * term-groups: add resizing constant * remove split pane css side-effect * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split-pane: remove `console.log` * split-pane: remove `console.log` * split panes: rebalance sizes on insert/removal * split panes: pass existing hterm instances to Term * split panes: add keybindings for split pane cycling * split panes: remove unused action * split panes: remove unused styling * split panes: rebalance sizes on insert/removal * split panes: set a minimum size for resizing * split-pane: fix vertical splits * css :| * package: bump electron * split panes: attach onFocus listener to webviews * 1.4.1 and 1.4.2 are broken. they have the following regression: - open google.com on the main window - open a new tab - come back to previous tab. webview is gone :| * split panes: handle PTY exits * split panes: add linux friendly keybindings
2016-10-03 18:00:50 -08:00
display: 'block',
2016-07-13 12:44:24 -08:00
width: '100%',
height: '100%'
},
2017-08-02 11:05:47 -08:00
wrapper: {
// TODO: decide whether to keep this or not based on
// understanding what xterm-selection is for
overflow: 'hidden'
},
2017-06-11 02:42:39 -08:00
term: {}
2016-07-13 12:44:24 -08:00
};
2016-06-30 22:01:04 -08:00
}
}