Merge pull request #3179 from weaveworks/3178-fix-terminal-viewport

Adjusted terminal character width/height estimation
This commit is contained in:
Filip Barl
2018-05-21 17:30:16 +02:00
committed by GitHub
2 changed files with 15 additions and 65 deletions

View File

@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import classNames from 'classnames';
import { debounce } from 'lodash';
import { Terminal as Term } from 'xterm';
import * as fit from 'xterm/lib/addons/fit/fit';
import { closeTerminal } from '../actions/app-actions';
import { getNeutralColor } from '../utils/color-utils';
@@ -30,32 +31,6 @@ function ab2str(buf) {
return decodedString;
}
function terminalCellSize(wrapperNode) {
// Badly guess the width/height of the row.
let characterWidth = 20;
let characterHeight = 20;
// Now try and measure the first row we find.
const subjectRow = wrapperNode.querySelector('.terminal .xterm-rows div');
if (!subjectRow) {
log("ERROR: Couldn't find first row, resizing might not work very well.");
} else {
const rowDisplay = subjectRow.style.display;
const contentBuffer = subjectRow.innerHTML;
subjectRow.innerHTML = 'W';
subjectRow.style.display = 'inline';
characterWidth = subjectRow.getBoundingClientRect().width;
subjectRow.style.display = rowDisplay;
characterHeight = parseInt(subjectRow.offsetHeight, 10);
subjectRow.innerHTML = contentBuffer;
}
log('Calculated (charWidth, charHeight) sizes in px: ', characterWidth, characterHeight);
return {characterWidth, characterHeight};
}
function openNewWindow(url, bcr, minWidth = 200) {
const screenLeft = window.screenX || window.screenLeft;
const screenTop = window.screenY || window.screenTop;
@@ -89,8 +64,6 @@ class Terminal extends React.Component {
detached: false,
rows: DEFAULT_ROWS,
cols: DEFAULT_COLS,
characterWidth: 0,
characterHeight: 0
};
this.handleCloseClick = this.handleCloseClick.bind(this);
@@ -171,9 +144,8 @@ class Terminal extends React.Component {
}
mountTerminal() {
Term.applyAddon(fit);
this.term = new Term({
cols: this.state.cols,
rows: this.state.rows,
convertEol: !this.props.pipe.get('raw'),
cursorBlink: true,
scrollback: 10000,
@@ -188,17 +160,19 @@ class Terminal extends React.Component {
}
});
this.createWebsocket(this.term);
this.term.on('resize', ({ cols, rows }) => {
const resizeTtyControl = this.props.pipe.get('resizeTtyControl');
if (resizeTtyControl) {
doResizeTty(this.getPipeId(), resizeTtyControl, cols, rows);
}
this.setState({ cols, rows });
});
const {characterWidth, characterHeight} = terminalCellSize(this.term.element);
this.createWebsocket(this.term);
window.addEventListener('resize', this.handleResizeDebounced);
this.resizeTimeout = setTimeout(() => {
this.setState({
characterWidth,
characterHeight
});
this.handleResize();
}, 10);
}
@@ -231,14 +205,7 @@ class Terminal extends React.Component {
}
}
componentDidUpdate(prevProps, prevState) {
const sizeChanged = (
prevState.cols !== this.state.cols ||
prevState.rows !== this.state.rows
);
if (sizeChanged) {
this.term.resize(this.state.cols, this.state.rows);
}
componentDidUpdate() {
if (!this.isEmbedded()) {
setDocumentTitle(this.getTitle());
}
@@ -256,24 +223,11 @@ class Terminal extends React.Component {
this.setState({detached: true});
const bcr = this.node.getBoundingClientRect();
const minWidth = (this.state.characterWidth * 80) + (8 * 2);
openNewWindow(`${basePath(window.location.pathname)}/terminal.html#!/state/${paramString}`, bcr, minWidth);
openNewWindow(`${basePath(window.location.pathname)}/terminal.html#!/state/${paramString}`, bcr);
}
handleResize() {
// scrollbar === 16px
const width = this.innerFlex.clientWidth - (2 * 8) - 16;
const height = this.innerFlex.clientHeight - (2 * 8);
const cols = Math.floor(width / this.state.characterWidth);
const rows = Math.floor(height / this.state.characterHeight);
const resizeTtyControl = this.props.pipe.get('resizeTtyControl');
if (resizeTtyControl) {
doResizeTty(this.getPipeId(), resizeTtyControl, cols, rows)
.then(() => this.setState({cols, rows}));
} else if (!this.props.pipe.get('raw')) {
this.setState({cols, rows});
}
this.term.fit();
}
isEmbedded() {
@@ -352,9 +306,6 @@ class Terminal extends React.Component {
opacity: this.state.connected ? 1 : 0.8,
overflow: 'hidden',
};
const innerStyle = {
width: (this.state.cols + 2) * this.state.characterWidth
};
const innerClassName = classNames('terminal-inner hideable', {
'terminal-inactive': !this.state.connected
});
@@ -362,9 +313,7 @@ class Terminal extends React.Component {
return (
<div className="terminal-wrapper" ref={this.saveNodeRef}>
{this.isEmbedded() && this.getTerminalHeader()}
<div className={innerClassName} style={innerFlexStyle} ref={this.saveInnerFlexRef}>
<div style={innerStyle} />
</div>
<div className={innerClassName} style={innerFlexStyle} ref={this.saveInnerFlexRef} />
{this.getTerminalStatusBar()}
</div>
);

View File

@@ -1303,6 +1303,7 @@ a {
right: 0;
background-color: $color-black;
padding: 8px;
box-sizing: content-box;
border-bottom-left-radius: $border-radius-soft;
.terminal {