2016-07-13 12:44:24 -08:00
|
|
|
import Immutable from 'seamless-immutable';
|
2016-09-21 06:27:11 -08:00
|
|
|
import {decorateUIReducer} from '../utils/plugins';
|
|
|
|
|
import {CONFIG_LOAD, CONFIG_RELOAD} from '../constants/config';
|
2016-07-19 10:30:57 -08:00
|
|
|
import {
|
|
|
|
|
UI_FONT_SIZE_SET,
|
|
|
|
|
UI_FONT_SIZE_RESET,
|
2016-08-06 02:01:01 -08:00
|
|
|
UI_FONT_SMOOTHING_SET,
|
|
|
|
|
UI_WINDOW_MAXIMIZE,
|
|
|
|
|
UI_WINDOW_UNMAXIMIZE
|
2016-07-19 10:30:57 -08:00
|
|
|
} from '../constants/ui';
|
2016-10-04 11:41:54 -08:00
|
|
|
import {NOTIFICATION_MESSAGE, NOTIFICATION_DISMISS} from '../constants/notifications';
|
2016-07-13 12:44:24 -08:00
|
|
|
import {
|
|
|
|
|
SESSION_ADD,
|
|
|
|
|
SESSION_RESIZE,
|
|
|
|
|
SESSION_PTY_DATA,
|
|
|
|
|
SESSION_PTY_EXIT,
|
2016-07-19 09:45:28 -08:00
|
|
|
SESSION_SET_ACTIVE,
|
|
|
|
|
SESSION_SET_CWD
|
2016-07-13 12:44:24 -08:00
|
|
|
} from '../constants/sessions';
|
2016-09-21 06:27:11 -08:00
|
|
|
import {UPDATE_AVAILABLE} from '../constants/updater';
|
|
|
|
|
import {values} from '../utils/object';
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-08-05 14:30:40 -08:00
|
|
|
const allowedCursorShapes = new Set(['BEAM', 'BLOCK', 'UNDERLINE']);
|
|
|
|
|
const allowedBells = new Set(['SOUND', false]);
|
2016-07-21 15:15:23 -08:00
|
|
|
|
2016-10-25 05:04:37 -08:00
|
|
|
// Populate `config-default.js` from this :)
|
2016-07-13 12:44:24 -08:00
|
|
|
const initial = Immutable({
|
|
|
|
|
cols: null,
|
|
|
|
|
rows: null,
|
|
|
|
|
activeUid: null,
|
|
|
|
|
cursorColor: '#F81CE5',
|
2016-07-21 15:15:23 -08:00
|
|
|
cursorShape: 'BLOCK',
|
2016-07-13 12:44:24 -08:00
|
|
|
borderColor: '#333',
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
padding: '12px 14px',
|
|
|
|
|
fontFamily: 'Menlo, "DejaVu Sans Mono", "Lucida Console", monospace',
|
|
|
|
|
fontSizeOverride: null,
|
2016-07-19 10:30:57 -08:00
|
|
|
fontSmoothingOverride: 'antialiased',
|
2016-07-13 12:44:24 -08:00
|
|
|
css: '',
|
|
|
|
|
termCSS: '',
|
|
|
|
|
openAt: {},
|
|
|
|
|
resizeAt: 0,
|
2016-07-21 11:24:00 -08:00
|
|
|
colors: {
|
|
|
|
|
black: '#000000',
|
|
|
|
|
red: '#ff0000',
|
|
|
|
|
green: '#33ff00',
|
|
|
|
|
yellow: '#ffff00',
|
|
|
|
|
blue: '#0066ff',
|
|
|
|
|
magenta: '#cc00ff',
|
|
|
|
|
cyan: '#00ffff',
|
|
|
|
|
white: '#d0d0d0',
|
|
|
|
|
lightBlack: '#808080',
|
|
|
|
|
lightRed: '#ff0000',
|
|
|
|
|
lightGreen: '#33ff00',
|
|
|
|
|
lightYellow: '#ffff00',
|
|
|
|
|
lightBlue: '#0066ff',
|
|
|
|
|
lightMagenta: '#cc00ff',
|
|
|
|
|
lightCyan: '#00ffff',
|
|
|
|
|
lightWhite: '#ffffff'
|
|
|
|
|
},
|
2016-07-13 12:44:24 -08:00
|
|
|
activityMarkers: {},
|
|
|
|
|
notifications: {
|
|
|
|
|
font: false,
|
|
|
|
|
resize: false,
|
2016-10-04 11:41:54 -08:00
|
|
|
updates: false,
|
|
|
|
|
message: false
|
2016-07-13 12:44:24 -08:00
|
|
|
},
|
|
|
|
|
foregroundColor: '#fff',
|
|
|
|
|
backgroundColor: '#000',
|
2016-08-06 02:01:01 -08:00
|
|
|
maximized: false,
|
2016-07-13 12:44:24 -08:00
|
|
|
updateVersion: null,
|
2016-08-05 14:30:40 -08:00
|
|
|
updateNotes: null,
|
2016-10-04 11:41:54 -08:00
|
|
|
messageText: null,
|
|
|
|
|
messageURL: null,
|
|
|
|
|
messageDismissable: null,
|
2016-08-05 14:30:40 -08:00
|
|
|
bell: 'SOUND',
|
2016-08-13 13:03:44 -08:00
|
|
|
bellSoundURL: 'lib-resource:hterm/audio/bell',
|
2016-09-30 04:30:11 -08:00
|
|
|
copyOnSelect: false,
|
|
|
|
|
modifierKeys: {
|
|
|
|
|
altIsMeta: false,
|
|
|
|
|
cmdIsMeta: false
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const reducer = (state = initial, action) => {
|
|
|
|
|
let state_ = state;
|
|
|
|
|
|
2016-09-21 06:27:11 -08:00
|
|
|
switch (action.type) { // eslint-disable-line default-case
|
2016-07-13 12:44:24 -08:00
|
|
|
case CONFIG_LOAD:
|
2016-09-21 06:27:11 -08:00
|
|
|
case CONFIG_RELOAD: // eslint-disable-line no-case-declarations
|
|
|
|
|
const {config} = action;
|
2016-07-13 12:44:24 -08:00
|
|
|
state_ = state
|
2016-10-10 02:26:47 -08:00
|
|
|
// unset the user font size override if the
|
2016-07-29 12:40:46 -08:00
|
|
|
// font size changed from the config
|
|
|
|
|
.merge((() => {
|
|
|
|
|
const ret = {};
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-07-29 12:40:46 -08:00
|
|
|
if (state.fontSizeOverride && config.fontSize !== state.fontSize) {
|
|
|
|
|
ret.fontSizeOverride = null;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.fontSize) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.fontSize = config.fontSize;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.fontFamily) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.fontFamily = config.fontFamily;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.cursorColor) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.cursorColor = config.cursorColor;
|
|
|
|
|
}
|
2016-07-21 15:15:23 -08:00
|
|
|
|
2016-08-05 14:30:40 -08:00
|
|
|
if (allowedCursorShapes.has(config.cursorShape)) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.cursorShape = config.cursorShape;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.borderColor) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.borderColor = config.borderColor;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-16 12:13:25 -08:00
|
|
|
if (typeof (config.padding) !== 'undefined' &&
|
|
|
|
|
config.padding !== null) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.padding = config.padding;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.foregroundColor) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.foregroundColor = config.foregroundColor;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.backgroundColor) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.backgroundColor = config.backgroundColor;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.css) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.css = config.css;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.termCSS) {
|
2016-07-29 12:40:46 -08:00
|
|
|
ret.termCSS = config.termCSS;
|
|
|
|
|
}
|
2016-07-21 11:24:00 -08:00
|
|
|
|
2016-08-05 14:30:40 -08:00
|
|
|
if (allowedBells.has(config.bell)) {
|
|
|
|
|
ret.bell = config.bell;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.bellSoundURL) {
|
2016-08-05 14:30:40 -08:00
|
|
|
ret.bellSoundURL = config.bellSoundURL || initial.bellSoundURL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-16 12:13:25 -08:00
|
|
|
if (typeof (config.copyOnSelect) !== 'undefined' &&
|
|
|
|
|
config.copyOnSelect !== null) {
|
2016-08-13 13:03:44 -08:00
|
|
|
ret.copyOnSelect = config.copyOnSelect;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.colors) {
|
2016-07-29 12:40:46 -08:00
|
|
|
if (Array.isArray(config.colors)) {
|
2016-09-21 06:27:11 -08:00
|
|
|
const stateColors = Array.isArray(state.colors) ?
|
|
|
|
|
state.colors :
|
|
|
|
|
values(state.colors);
|
2016-07-29 12:40:46 -08:00
|
|
|
|
|
|
|
|
if (stateColors.toString() !== config.colors.toString()) {
|
|
|
|
|
ret.colors = config.colors;
|
|
|
|
|
}
|
2016-09-21 06:27:11 -08:00
|
|
|
} else if (JSON.stringify(state.colors) !== JSON.stringify(config.colors)) {
|
|
|
|
|
ret.colors = config.colors;
|
2016-07-21 11:24:00 -08:00
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-04 10:16:34 -08:00
|
|
|
if (config.modifierKeys) {
|
2016-09-30 04:30:11 -08:00
|
|
|
ret.modifierKeys = config.modifierKeys;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 12:40:46 -08:00
|
|
|
return ret;
|
|
|
|
|
})());
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_ADD:
|
|
|
|
|
state_ = state.merge({
|
2016-10-05 08:20:08 -08:00
|
|
|
activeUid: action.uid,
|
2016-07-13 12:44:24 -08:00
|
|
|
openAt: {
|
|
|
|
|
[action.uid]: Date.now()
|
|
|
|
|
}
|
2016-09-21 06:27:11 -08:00
|
|
|
}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_RESIZE:
|
2016-10-10 02:26:47 -08:00
|
|
|
// only care about the sizes
|
2016-10-03 18:00:50 -08:00
|
|
|
// of standalone terms (i.e. not splits):
|
|
|
|
|
if (!action.isStandaloneTerm) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-13 12:44:24 -08:00
|
|
|
state_ = state.merge({
|
|
|
|
|
rows: action.rows,
|
|
|
|
|
cols: action.cols,
|
|
|
|
|
resizeAt: Date.now()
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_PTY_EXIT:
|
|
|
|
|
state_ = state
|
2016-09-21 06:27:11 -08:00
|
|
|
.updateIn(['openAt'], times => {
|
2016-07-29 12:40:46 -08:00
|
|
|
const times_ = times.asMutable();
|
|
|
|
|
delete times_[action.uid];
|
|
|
|
|
return times_;
|
|
|
|
|
})
|
2016-09-21 06:27:11 -08:00
|
|
|
.updateIn(['activityMarkers'], markers => {
|
2016-07-29 12:40:46 -08:00
|
|
|
const markers_ = markers.asMutable();
|
|
|
|
|
delete markers_[action.uid];
|
|
|
|
|
return markers_;
|
|
|
|
|
});
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_SET_ACTIVE:
|
|
|
|
|
state_ = state.merge({
|
|
|
|
|
activeUid: action.uid,
|
|
|
|
|
activityMarkers: {
|
|
|
|
|
[action.uid]: false
|
|
|
|
|
}
|
2016-09-21 06:27:11 -08:00
|
|
|
}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
2016-09-21 06:27:11 -08:00
|
|
|
case SESSION_PTY_DATA: // eslint-disable-line no-case-declarations
|
2016-07-13 12:44:24 -08:00
|
|
|
// ignore activity markers for current tab
|
2016-09-21 06:27:11 -08:00
|
|
|
if (action.uid === state.activeUid) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
|
|
|
|
// current time for comparisons
|
2016-09-21 06:27:11 -08:00
|
|
|
const now = Date.now();
|
2016-07-13 12:44:24 -08:00
|
|
|
|
|
|
|
|
// if first data events after open, ignore
|
2016-09-21 06:27:11 -08:00
|
|
|
if (now - state.openAt[action.uid] < 1000) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-13 12:44:24 -08:00
|
|
|
|
2016-10-10 02:26:47 -08:00
|
|
|
// ignore activity markers that are within
|
2016-07-13 12:44:24 -08:00
|
|
|
// proximity of a resize event, since we
|
|
|
|
|
// expect to get data packets from the resize
|
|
|
|
|
// of the ptys as a result
|
|
|
|
|
if (!state.resizeAt || now - state.resizeAt > 1000) {
|
|
|
|
|
state_ = state.merge({
|
|
|
|
|
activityMarkers: {
|
|
|
|
|
[action.uid]: true
|
|
|
|
|
}
|
2016-09-21 06:27:11 -08:00
|
|
|
}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-19 09:45:28 -08:00
|
|
|
case SESSION_SET_CWD:
|
|
|
|
|
state_ = state.set('cwd', action.cwd);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-13 12:44:24 -08:00
|
|
|
case UI_FONT_SIZE_SET:
|
2016-07-13 21:37:46 -08:00
|
|
|
state_ = state.set('fontSizeOverride', action.value);
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UI_FONT_SIZE_RESET:
|
|
|
|
|
state_ = state.set('fontSizeOverride', null);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-19 10:30:57 -08:00
|
|
|
case UI_FONT_SMOOTHING_SET:
|
|
|
|
|
state_ = state.set('fontSmoothingOverride', action.fontSmoothing);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-06 02:01:01 -08:00
|
|
|
case UI_WINDOW_MAXIMIZE:
|
|
|
|
|
state_ = state.set('maximized', true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UI_WINDOW_UNMAXIMIZE:
|
|
|
|
|
state_ = state.set('maximized', false);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-13 12:44:24 -08:00
|
|
|
case NOTIFICATION_DISMISS:
|
|
|
|
|
state_ = state.merge({
|
|
|
|
|
notifications: {
|
|
|
|
|
[action.id]: false
|
|
|
|
|
}
|
2016-09-21 06:27:11 -08:00
|
|
|
}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
break;
|
|
|
|
|
|
2016-10-04 11:41:54 -08:00
|
|
|
case NOTIFICATION_MESSAGE:
|
|
|
|
|
state_ = state.merge({
|
|
|
|
|
messageText: action.text,
|
2016-10-04 12:27:27 -08:00
|
|
|
messageURL: action.url,
|
2016-10-04 11:41:54 -08:00
|
|
|
messageDismissable: action.dismissable === true
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-13 12:44:24 -08:00
|
|
|
case UPDATE_AVAILABLE:
|
|
|
|
|
state_ = state.merge({
|
|
|
|
|
updateVersion: action.version,
|
|
|
|
|
updateNotes: action.notes || ''
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-10 02:26:47 -08:00
|
|
|
// Show a notification if any of the font size values have changed
|
2016-07-13 12:44:24 -08:00
|
|
|
if (CONFIG_LOAD !== action.type) {
|
|
|
|
|
if (state_.fontSize !== state.fontSize ||
|
|
|
|
|
state_.fontSizeOverride !== state.fontSizeOverride) {
|
2016-09-21 06:27:11 -08:00
|
|
|
state_ = state_.merge({notifications: {font: true}}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-16 12:13:25 -08:00
|
|
|
if ((typeof (state.cols) !== 'undefined' && state.cols !== null) &&
|
|
|
|
|
(typeof (state.rows) !== 'undefined' && state.rows !== null) &&
|
|
|
|
|
(state.rows !== state_.rows || state.cols !== state_.cols)) {
|
2016-09-21 06:27:11 -08:00
|
|
|
state_ = state_.merge({notifications: {resize: true}}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-04 11:41:54 -08:00
|
|
|
if (state.messageText !== state_.messageText || state.messageURL !== state_.messageURL) {
|
|
|
|
|
state_ = state_.merge({notifications: {message: true}}, {deep: true});
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-13 12:44:24 -08:00
|
|
|
if (state.updateVersion !== state_.updateVersion) {
|
2016-09-21 06:27:11 -08:00
|
|
|
state_ = state_.merge({notifications: {updates: true}}, {deep: true});
|
2016-07-13 12:44:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return state_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default decorateUIReducer(reducer);
|