hyper/lib/actions/term-groups.js
2018-04-16 07:17:17 -07:00

173 lines
4.8 KiB
JavaScript

import rpc from '../rpc';
import {
DIRECTION,
TERM_GROUP_RESIZE,
TERM_GROUP_REQUEST,
TERM_GROUP_EXIT,
TERM_GROUP_EXIT_ACTIVE
} from '../constants/term-groups';
import {SESSION_REQUEST} from '../constants/sessions';
import findBySession from '../utils/term-groups';
import getRootGroups from '../selectors';
import {setActiveSession, ptyExitSession, userExitSession} from './sessions';
function requestSplit(direction) {
return () => (dispatch, getState) => {
dispatch({
type: SESSION_REQUEST,
effect: () => {
const {ui} = getState();
rpc.emit('new', {
splitDirection: direction,
cwd: ui.cwd
});
}
});
};
}
export const requestVerticalSplit = requestSplit(DIRECTION.VERTICAL);
export const requestHorizontalSplit = requestSplit(DIRECTION.HORIZONTAL);
export function resizeTermGroup(uid, sizes) {
return {
uid,
type: TERM_GROUP_RESIZE,
sizes
};
}
export function requestTermGroup() {
return (dispatch, getState) => {
dispatch({
type: TERM_GROUP_REQUEST,
effect: () => {
const {ui} = getState();
const {cols, rows, cwd} = ui;
rpc.emit('new', {
isNewGroup: true,
cols,
rows,
cwd
});
}
});
};
}
export function setActiveGroup(uid) {
return (dispatch, getState) => {
const {termGroups} = getState();
dispatch(setActiveSession(termGroups.activeSessions[uid]));
};
}
// When we've found the next group which we want to
// set as active (after closing something), we also need
// to find the first child group which has a sessionUid.
const findFirstSession = (state, group) => {
if (group.sessionUid) {
return group.sessionUid;
}
for (const childUid of group.children) {
const child = state.termGroups[childUid];
// We want to find the *leftmost* session,
// even if it's nested deep down:
const sessionUid = findFirstSession(state, child);
if (sessionUid) {
return sessionUid;
}
}
};
const findPrevious = (list, old) => {
const index = list.indexOf(old);
// If `old` was the first item in the list,
// choose the other item available:
return index ? list[index - 1] : list[1];
};
const findNextSessionUid = (state, group) => {
// If we're closing a root group (i.e. a whole tab),
// the next group needs to be a root group as well:
if (state.activeRootGroup === group.uid) {
const rootGroups = getRootGroups({termGroups: state});
const nextGroup = findPrevious(rootGroups, group);
return findFirstSession(state, nextGroup);
}
const {children} = state.termGroups[group.parentUid];
const nextUid = findPrevious(children, group.uid);
return findFirstSession(state, state.termGroups[nextUid]);
};
export function ptyExitTermGroup(sessionUid) {
return (dispatch, getState) => {
const {termGroups} = getState();
const group = findBySession(termGroups, sessionUid);
// This might have already been closed:
if (!group) {
return dispatch(ptyExitSession(sessionUid));
}
dispatch({
type: TERM_GROUP_EXIT,
uid: group.uid,
effect: () => {
const activeSessionUid = termGroups.activeSessions[termGroups.activeRootGroup];
if (Object.keys(termGroups.termGroups).length > 1 && activeSessionUid === sessionUid) {
const nextSessionUid = findNextSessionUid(termGroups, group);
dispatch(setActiveSession(nextSessionUid));
}
dispatch(ptyExitSession(sessionUid));
}
});
};
}
export function userExitTermGroup(uid) {
return (dispatch, getState) => {
const {termGroups} = getState();
dispatch({
type: TERM_GROUP_EXIT,
uid,
effect: () => {
const group = termGroups.termGroups[uid];
if (Object.keys(termGroups.termGroups).length <= 1) {
// No need to attempt finding a new active session
// if this is the last one we've got:
return dispatch(userExitSession(group.sessionUid));
}
const activeSessionUid = termGroups.activeSessions[termGroups.activeRootGroup];
if (termGroups.activeRootGroup === uid || activeSessionUid === group.sessionUid) {
const nextSessionUid = findNextSessionUid(termGroups, group);
dispatch(setActiveSession(nextSessionUid));
}
if (group.sessionUid) {
dispatch(userExitSession(group.sessionUid));
} else {
group.children.forEach(childUid => {
dispatch(userExitTermGroup(childUid));
});
}
}
});
};
}
export function exitActiveTermGroup() {
return (dispatch, getState) => {
dispatch({
type: TERM_GROUP_EXIT_ACTIVE,
effect() {
const {sessions, termGroups} = getState();
const {uid} = findBySession(termGroups, sessions.activeUid);
dispatch(userExitTermGroup(uid));
}
});
};
}