mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-13 12:38:39 -09:00
* Dynamically change the `font-smoothing` pref By default, hterm defaults to `font-smoothing: 'antialiased'`, which works really well on retina displays. On non-retina displays, however, the type looks very thin and is hard to read. This will look at the devicePixelRatio of the device anytime the term prefs are set, and change between `antialiased` and `subpixel-antialiased` dynamically. * Refactor to add the font smoothing override into state This also subscribes to the electron `move` event to control when this piece of state gets updated. * Add UI_WINDOW_MOVE action with a side effect for font smoothing
189 lines
4.9 KiB
JavaScript
189 lines
4.9 KiB
JavaScript
import React from 'react';
|
|
import Term_ from './term';
|
|
import Component from '../component';
|
|
import { last } from '../utils/array';
|
|
import { decorate, getTermProps } from '../utils/plugins';
|
|
|
|
const Term = decorate(Term_, 'Term');
|
|
|
|
export default class Terms extends Component {
|
|
|
|
constructor (props, context) {
|
|
super(props, context);
|
|
this.terms = {};
|
|
this.bound = new WeakMap();
|
|
this.onRef = this.onRef.bind(this);
|
|
props.ref_(this);
|
|
}
|
|
|
|
componentWillReceiveProps (next) {
|
|
const { write } = next;
|
|
if (write && this.props.write !== write) {
|
|
this.getTermByUid(write.uid).write(write.data);
|
|
}
|
|
|
|
// if we just rendered, we consider the first tab active
|
|
// why is this decided here? because what session becomes
|
|
// active is a *view* and *layout* concern. for example,
|
|
// if a split is closed (and we had split), the next active
|
|
// session after the close would be the one next to it
|
|
// *in the view*, not necessarily the model datastructure
|
|
if (next.sessions && next.sessions.length) {
|
|
if (!this.props.activeSession && next.sessions.length) {
|
|
this.props.onActive(next.sessions[0].uid);
|
|
} else if (this.props.sessions.length !== next.sessions.length) {
|
|
if (next.sessions.length > this.props.sessions.length) {
|
|
// if we are adding, we focused on the new one
|
|
this.props.onActive(last(next.sessions).uid);
|
|
return;
|
|
}
|
|
|
|
const newUids = uids(next.sessions);
|
|
const curActive = this.props.activeSession;
|
|
|
|
// if we closed an item that wasn't focused, nothing changes
|
|
if (~newUids.indexOf(curActive)) {
|
|
return;
|
|
}
|
|
|
|
const oldIndex = uids(this.props.sessions).indexOf(curActive);
|
|
if (newUids[oldIndex]) {
|
|
this.props.onActive(newUids[oldIndex]);
|
|
} else {
|
|
this.props.onActive(last(next.sessions).uid);
|
|
}
|
|
}
|
|
} else {
|
|
this.props.onActive(null);
|
|
}
|
|
}
|
|
|
|
shouldComponentUpdate (nextProps) {
|
|
for (const i in nextProps) {
|
|
if ('write' === i) continue;
|
|
if (this.props[i] !== nextProps[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
for (const i in this.props) {
|
|
if ('write' === i) continue;
|
|
if (this.props[i] !== nextProps[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
onRef (uid, term) {
|
|
if (term) {
|
|
this.terms[uid] = term;
|
|
} else {
|
|
delete this.terms[uid];
|
|
}
|
|
}
|
|
|
|
getTermByUid (uid) {
|
|
return this.terms[uid];
|
|
}
|
|
|
|
getActiveTerm () {
|
|
return this.getTermByUid(this.props.activeSession);
|
|
}
|
|
|
|
bind (fn, thisObj, uid) {
|
|
if (!this.bound.has(fn)) {
|
|
this.bound.set(fn, {});
|
|
}
|
|
const map = this.bound.get(fn);
|
|
if (!map[uid]) {
|
|
map[uid] = fn.bind(thisObj, uid);
|
|
}
|
|
return map[uid];
|
|
}
|
|
|
|
getTermProps (uid) {
|
|
return getTermProps(uid, this.props);
|
|
}
|
|
|
|
onTerminal (uid, term) {
|
|
this.terms[uid] = term;
|
|
}
|
|
|
|
componentWillUnmount () {
|
|
this.props.ref_(null);
|
|
}
|
|
|
|
template (css) {
|
|
return <div
|
|
style={{ padding: this.props.padding }}
|
|
className={ css('terms') }>
|
|
{ this.props.customChildrenBefore }
|
|
{
|
|
this.props.sessions.map((session) => {
|
|
const uid = session.uid;
|
|
const isActive = uid === this.props.activeSession;
|
|
const props = getTermProps(uid, this.props, {
|
|
cols: this.props.cols,
|
|
rows: this.props.rows,
|
|
customCSS: this.props.customCSS,
|
|
fontSize: this.props.fontSize,
|
|
cursorColor: this.props.cursorColor,
|
|
fontFamily: this.props.fontFamily,
|
|
fontSmoothing: this.props.fontSmoothing,
|
|
foregroundColor: this.props.foregroundColor,
|
|
backgroundColor: this.props.backgroundColor,
|
|
colors: this.props.colors,
|
|
url: session.url,
|
|
cleared: session.cleared,
|
|
onResize: this.bind(this.props.onResize, null, uid),
|
|
onTitle: this.bind(this.props.onTitle, null, uid),
|
|
onData: this.bind(this.props.onData, null, uid),
|
|
onURLAbort: this.bind(this.props.onURLAbort, null, uid)
|
|
});
|
|
return <div
|
|
key={`d${uid}`}
|
|
className={css('term', isActive && 'termActive')}>
|
|
<Term
|
|
key={uid}
|
|
ref_={this.bind(this.onRef, this, uid)}
|
|
{...props} />
|
|
</div>;
|
|
})
|
|
}
|
|
{ this.props.customChildren }
|
|
</div>;
|
|
}
|
|
|
|
styles () {
|
|
return {
|
|
terms: {
|
|
position: 'absolute',
|
|
marginTop: '34px',
|
|
top: 0,
|
|
right: 0,
|
|
left: 0,
|
|
bottom: 0,
|
|
color: '#fff'
|
|
},
|
|
|
|
term: {
|
|
display: 'none',
|
|
width: '100%',
|
|
height: '100%'
|
|
},
|
|
|
|
termActive: {
|
|
display: 'block'
|
|
}
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
// little memoized helper to compute a map of uids
|
|
function uids (sessions) {
|
|
if (!sessions._uids) {
|
|
sessions._uids = sessions.map((s) => s.uid);
|
|
}
|
|
return sessions._uids;
|
|
}
|