{"action":"created","issue":{"url":"https://api.github.com/repos/zeit/hyper/issues/693","repository_url":"https://api.github.com/repos/zeit/hyper","labels_url":"https://api.github.com/repos/zeit/hyper/issues/693/labels{/name}","comments_url":"https://api.github.com/repos/zeit/hyper/issues/693/comments","events_url":"https://api.github.com/repos/zeit/hyper/issues/693/events","html_url":"https://github.com/zeit/hyper/pull/693","id":175157190,"number":693,"title":"Split Panes","user":{"login":"ekmartin","id":3536982,"avatar_url":"https://avatars.githubusercontent.com/u/3536982?v=3","gravatar_id":"","url":"https://api.github.com/users/ekmartin","html_url":"https://github.com/ekmartin","followers_url":"https://api.github.com/users/ekmartin/followers","following_url":"https://api.github.com/users/ekmartin/following{/other_user}","gists_url":"https://api.github.com/users/ekmartin/gists{/gist_id}","starred_url":"https://api.github.com/users/ekmartin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekmartin/subscriptions","organizations_url":"https://api.github.com/users/ekmartin/orgs","repos_url":"https://api.github.com/users/ekmartin/repos","events_url":"https://api.github.com/users/ekmartin/events{/privacy}","received_events_url":"https://api.github.com/users/ekmartin/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/zeit/hyper/labels/Status:%20In%20Progress","name":"Status: In Progress","color":"79FF28"},{"url":"https://api.github.com/repos/zeit/hyper/labels/Status:%20Review%20Needed","name":"Status: Review Needed","color":"fbca04"}],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":19,"created_at":"2016-09-06T04:18:51Z","updated_at":"2016-10-19T20:34:22Z","closed_at":"2016-10-04T02:00:51Z","pull_request":{"url":"https://api.github.com/repos/zeit/hyper/pulls/693","html_url":"https://github.com/zeit/hyper/pull/693","diff_url":"https://github.com/zeit/hyper/pull/693.diff","patch_url":"https://github.com/zeit/hyper/pull/693.patch"},"body":"This adds an initial implementation of split panes, as shown in the screenshot below.\r\n![Split Panes](https://cloud.githubusercontent.com/assets/3536982/18260447/e388190e-73bb-11e6-8ccb-fa22c68b0920.png)\r\n\r\n## Features\r\n* Split panes can be created by hitting `Cmd+D` and `Cmd+Shift+D` (which are also accessible from the `Window` menu).\r\n* Split panes can be arbitrarily nested, and support tabs like you'd expect.\r\n* The active pane can be changed with mouse clicks, or by cycling through them using `Show Next Pane`/`Show Previous Pane`.\r\n* Panes can be closed with `CmdOrCtrl+W`.\r\n\r\n## How\r\nThere's definitely lots of ways to implement something like this, however I've opted for a pretty Redux heavy direction. The whole split pane structure is stored in a new reducer, `term-groups.js`, which reacts to create/remove/focus change actions and adapts the structure as needed.\r\n\r\n### Reducer Structure\r\nThe `term-groups` reducer maintains a tree like structure of the different tabs.\r\nThe split structure in the screenshot would resemble something like this:\r\n\r\n```\r\n   +-----+Root+----+\r\n   |               |\r\n   v               v\r\n++Left++       ++Right++\r\n|      |       |   +   |\r\nv      v       v   v   v\r\nS      S       S   S   S\r\n```\r\n\r\nEach term group would have the following properties:\r\n* `uid` - group identifier\r\n* `parentUid` - the parent's `uid`\r\n* `sessionUid` - if the group is a leaf node, conforms to the actual session's `uid`\r\n* `direction` - what direction the split is created in (only for internal nodes)\r\n* `children` - an array of uids of the term group's children.\r\n\r\nAdditionally, the reducer holds a mapping between each root term group and their respective active `sessionUid`, so that you can change tabs without losing the focus of the session you'd selected. \r\n\r\n### Caveats\r\nTo be able to create new term groups the `SESSION_ADD` action is hijacked, and the split direction (if it's a split that caused the new session to be created) is added [here](https://github.com/ekmartin/hyperterm/blob/splits/lib/actions/term-groups.js#L20-L23). This feels a bit dirty, and I'd love suggestions on how this could be improved (and suggestions on how to improve the data structure in general!).\r\n\r\n### Rendering\r\nThe actual split panes are rendered using [react-split-pane](https://github.com/tomkp/react-split-pane) at the moment, but this probably needs to be changed before this is ready for primetime. A few issues:\r\n* It doesn't support [more than two split panes](https://github.com/tomkp/react-split-pane/issues/81) out of the box without nesting split panes ([workaround](https://github.com/ekmartin/hyperterm/blob/splits/lib/components/term-group.js#L28-L47)).\r\n* The styling is a slightly awkward. This could be fixed with an upstream pull request to allow custom class names for the pane divider (resizer), so we could use it with Aphrodite.\r\n* Mouse resizing also seems a bit glitchy, but this might be an issue on our end as well - haven't spent too much time on it yet.\r\n\r\nWe could either look into fixing these issues upstream, or just implement our own flexbox heavy approach.\r\n\r\n## TODOs\r\n### ✅  Preserving already created hterm instances\r\nAt the moment we're creating hterm instances at the bottom of the React hierarchy, in the `Term` component. This doesn't work very well with split panes, since `Term`s will be removed and recreated when the split pane structure is changed. That means the same happens to their respective hterm instances, which means that sessions lose their output when splitting (i.e. needs to be fixed before splits are usable).\r\n\r\nOne of the ways of solving this would be to create hterm instances at a higher level, and then pass them down to the `Term` component. This could either be in a React component such as `Terms`, or even in a Redux reducer. The latter may sound a bit crazy, but I think it might make sense together with the current reducer structure. I'm interested in more ideas around this though.\r\n\r\n### ✅  Hotkeys\r\nThis definitely needs some bikeshedding. Even if we need a way of configuring hotkeys in the future, sane defaults will always be important. As mentioned splits are currently created with `CtrlOrCmd+D` and `CtrlOrCmd+Shift+D`. `Cmd+D` is definitely okay, but `Ctrl+D` obviously isn't 😙. Maybe we can change it based on the user's OS. What would be a decent hotkey set for Linux?\r\n\r\nThere also isn't a hotkey for rotating back and forth between your open split panes yet. iTerm defaults this to `Cmd+[`/`Cmd+]`, however this doesn't work on a lot of European keyboards. Personally I'd prefer something like `Ctrl+Tab`/`Ctrl+Shift+Tab`, which we've currently set to changing tabs (afaik it doesn't work though, the combination is eaten by hterm). \r\n\r\n**EDIT:** Cycling between split panes is currently bound to `Ctrl+Alt+Tab` and `Ctrl+Shift+Alt+Tab`.\r\n\r\nIn the future we should definitely also support changing panes based on direction (`Cmd+Alt+Arrow` in iTerm).\r\n\r\n### ✅  Resizing\r\nDrag and drop resizing of split panes sort of works at the moment, but it's really glitchy.\r\n\r\n### ✅  Styling\r\nNeeds to support custom styling in the same way as the rest of HyperTerm. We could probably add some sort of indicator to show what pane is in focus (i.e. an overlay over the inactive panes, like iTerm) as well.\r\n\r\n### Bugs\r\n- [x] Clicking to change focus doesn't work when applications such as `vtop/htop` are open.\r\n- [x] Splitting panes will make `git status` output look funky (and probably other resizing issues) - [screenshot](https://cloud.githubusercontent.com/assets/3536982/18336213/60507c2c-7553-11e6-9e44-53a98961f342.png).\r\n- [x] A tab will sometimes crash after a pane is closed, needs more investigation.\r\n- [x] Closing the last tab won't exit HyperTerm (regression).\r\n- [x] Creating multiple horizontal splits is buggy.\r\n- [x] Webviews don't respect focus changes as they should.\r\n\r\n...and probably a lot more!\r\n\r\n## Binary\r\nI really recommend pulling down the branch, however I've made a binary that can be downloaded here: https://github.com/ekmartin/hyperterm/releases/download/0.8.0-splits.5/mac.zip (updated 2016-10-02)"},"comment":{"url":"https://api.github.com/repos/zeit/hyper/issues/comments/254932502","html_url":"https://github.com/zeit/hyper/pull/693#issuecomment-254932502","issue_url":"https://api.github.com/repos/zeit/hyper/issues/693","id":254932502,"user":{"login":"iamstarkov","id":559321,"avatar_url":"https://avatars.githubusercontent.com/u/559321?v=3","gravatar_id":"","url":"https://api.github.com/users/iamstarkov","html_url":"https://github.com/iamstarkov","followers_url":"https://api.github.com/users/iamstarkov/followers","following_url":"https://api.github.com/users/iamstarkov/following{/other_user}","gists_url":"https://api.github.com/users/iamstarkov/gists{/gist_id}","starred_url":"https://api.github.com/users/iamstarkov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iamstarkov/subscriptions","organizations_url":"https://api.github.com/users/iamstarkov/orgs","repos_url":"https://api.github.com/users/iamstarkov/repos","events_url":"https://api.github.com/users/iamstarkov/events{/privacy}","received_events_url":"https://api.github.com/users/iamstarkov/received_events","type":"User","site_admin":false},"created_at":"2016-10-19T20:34:22Z","updated_at":"2016-10-19T20:34:22Z","body":"@naim though you need to download hyper. before it was hyperterm and has been renamed"}}
{"actor":{"display_login":"iamstarkov"}}