Skip to content

Commit 496cd42

Browse files
authored
fix(tiles): correct split logic and reattach sessions
Stability fix for tiled splits.
1 parent 2906a0a commit 496cd42

1 file changed

Lines changed: 84 additions & 72 deletions

File tree

src/public/panes.js

Lines changed: 84 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,10 @@ class PaneManager {
537537
else if (x > r.width * 0.72) dir = 'right';
538538
else if (y < r.height * 0.28) dir = 'top';
539539
else if (y > r.height * 0.72) dir = 'bottom';
540+
const sourcePane = parseInt(e.dataTransfer.getData('x-source-pane') || '-1', 10);
540541
if (dir) {
541542
this.splitAt(index, dir, sid, copy);
542543
} else {
543-
const sourcePane = parseInt(e.dataTransfer.getData('x-source-pane') || '-1', 10);
544544
this.assignSession(index, sid);
545545
if (!copy && !isNaN(sourcePane) && sourcePane >= 0 && sourcePane !== index) this.removeTabFromPane(sourcePane, sid);
546546
}
@@ -752,6 +752,13 @@ class PaneManager {
752752
this.panes[i].container = document.getElementById(`tileTerminal${i}`);
753753
}
754754
}
755+
// Reattach active sessions to their (possibly re-rendered) terminals
756+
for (let i = 0; i < this.tabs.length; i++) {
757+
const t = this.tabs[i];
758+
if (t && t.active) {
759+
try { this.panes[i]?.setSession(t.active); } catch (_) {}
760+
}
761+
}
755762
}
756763

757764
removeTabFromPane(index, sid) {
@@ -832,99 +839,104 @@ class PaneManager {
832839
splitEdge(direction, sid, copy, sourcePane) {
833840
if (direction === 'left') {
834841
if (this.rows * (this.cols + 1) > this.maxPanes) return;
835-
this.cols += 1; this.widths = Array(this.cols).fill(100 / this.cols);
836-
const newPanes = []; const newTabs = [];
837-
for (let r = 0; r < this.rows; r++) {
838-
// empty first column
839-
newPanes.push(new ClaudePane(newPanes.length, this.app)); newTabs.push({ list: [], active: null });
840-
for (let c = 0; c < this.cols - 1; c++) {
841-
const oldIdx = r * (this.cols - 1) + c;
842-
newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]);
843-
}
844-
}
845-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
846-
this.assignSession(0, sid);
842+
this.insertColumn(0);
843+
const target = 0; // top-left
844+
this.assignSession(target, sid);
847845
if (!copy && !isNaN(sourcePane) && sourcePane >= 0) this.removeTabFromPane(sourcePane, sid);
848846
} else if (direction === 'right') {
849847
if (this.rows * (this.cols + 1) > this.maxPanes) return;
850-
this.cols += 1; this.widths = Array(this.cols).fill(100 / this.cols);
851-
for (let r = 0; r < this.rows; r++) { this.panes.push(new ClaudePane(this.panes.length, this.app)); this.tabs.push({ list: [], active: null }); }
852-
this.rebuildGrid();
853-
const target = this.cols - 1; this.assignSession(target, sid);
848+
this.insertColumn(this.cols - 1);
849+
const target = this.cols - 1; // top-right
850+
this.assignSession(target, sid);
854851
if (!copy && !isNaN(sourcePane) && sourcePane >= 0) this.removeTabFromPane(sourcePane, sid);
855852
} else if (direction === 'top') {
856853
if ((this.rows + 1) * this.cols > this.maxPanes) return;
857-
if (this.rows === 1) { this.rows = 2; this.heights = [50, 50]; }
858-
// prepend empty row
859-
const newPanes = []; const newTabs = [];
860-
for (let c = 0; c < this.cols; c++) { newPanes.push(new ClaudePane(newPanes.length, this.app)); newTabs.push({ list: [], active: null }); }
861-
for (let c = 0; c < this.cols; c++) { const oldIdx = c; newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]); }
862-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
863-
this.assignSession(0, sid);
854+
this.insertRow(0);
855+
const target = 0; // top-left
856+
this.assignSession(target, sid);
864857
if (!copy && !isNaN(sourcePane) && sourcePane >= 0) this.removeTabFromPane(sourcePane, sid);
865858
} else if (direction === 'bottom') {
866859
if ((this.rows + 1) * this.cols > this.maxPanes) return;
867-
if (this.rows === 1) { this.rows = 2; this.heights = [50, 50]; }
868-
for (let c = 0; c < this.cols; c++) { this.panes.push(new ClaudePane(this.panes.length, this.app)); this.tabs.push({ list: [], active: null }); }
869-
this.rebuildGrid();
870-
const target = (this.rows - 1) * this.cols; this.assignSession(target, sid);
860+
this.insertRow(this.rows - 1);
861+
const target = (this.rows - 1) * this.cols; // bottom-left
862+
this.assignSession(target, sid);
871863
if (!copy && !isNaN(sourcePane) && sourcePane >= 0) this.removeTabFromPane(sourcePane, sid);
872864
}
873865
}
874866

875867
// Split a specific cell in a given direction
876868
splitAt(index, direction, sid, copy = false) {
877-
const col = index % this.cols; const row = Math.floor(index / this.cols);
869+
const oldCols = this.cols; const oldRows = this.rows;
870+
const col = index % oldCols; const row = Math.floor(index / oldCols);
878871
if (direction === 'left') {
879-
if (this.rows * (this.cols + 1) > this.maxPanes) return;
880-
this.cols += 1; this.widths = Array(this.cols).fill(100 / this.cols);
881-
const newPanes = []; const newTabs = [];
882-
for (let r = 0; r < this.rows; r++) {
883-
for (let c = 0; c < this.cols; c++) {
884-
if (c === col) { newPanes.push(new ClaudePane(newPanes.length, this.app)); newTabs.push({ list: [], active: null }); }
885-
const oldIdx = r * (this.cols - 1) + (c > col ? c - 1 : c);
886-
newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]);
887-
}
888-
}
889-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
890-
const target = row * this.cols + col; this.assignSession(target, sid);
891-
if (!copy) this.removeTabFromPane(index + 1, sid);
872+
if (oldRows * (oldCols + 1) > this.maxPanes) return;
873+
this.insertColumn(col - 1 < 0 ? 0 : col - 1);
874+
const target = row * this.cols + col;
875+
const srcAfter = row * this.cols + (col + 1);
876+
this.assignSession(target, sid);
877+
if (!copy) this.removeTabFromPane(srcAfter, sid);
892878
} else if (direction === 'right') {
893-
if (this.rows * (this.cols + 1) > this.maxPanes) return;
894-
this.cols += 1; this.widths = Array(this.cols).fill(100 / this.cols);
895-
const newPanes = []; const newTabs = [];
896-
for (let r = 0; r < this.rows; r++) {
897-
for (let c = 0; c < this.cols; c++) {
898-
const oldIdx = r * (this.cols - 1) + (c <= col ? c : c - 1);
899-
newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]);
879+
if (oldRows * (oldCols + 1) > this.maxPanes) return;
880+
this.insertColumn(col);
881+
const target = row * this.cols + (col + 1);
882+
const srcAfter = row * this.cols + col;
883+
this.assignSession(target, sid);
884+
if (!copy) this.removeTabFromPane(srcAfter, sid);
885+
} else if (direction === 'top') {
886+
if ((oldRows + 1) * oldCols > this.maxPanes) return;
887+
this.insertRow(row - 1 < 0 ? 0 : row - 1);
888+
const target = row * this.cols + col;
889+
const srcAfter = (row + 1) * this.cols + col;
890+
this.assignSession(target, sid);
891+
if (!copy) this.removeTabFromPane(srcAfter, sid);
892+
} else if (direction === 'bottom') {
893+
if ((oldRows + 1) * oldCols > this.maxPanes) return;
894+
this.insertRow(row);
895+
const target = (row + 1) * this.cols + col;
896+
const srcAfter = row * this.cols + col;
897+
this.assignSession(target, sid);
898+
if (!copy) this.removeTabFromPane(srcAfter, sid);
899+
}
900+
}
901+
902+
insertColumn(insertAfterCol) {
903+
const oldCols = this.cols; const rows = this.rows;
904+
const oldPanes = this.panes.slice(); const oldTabs = this.tabs.map(t => ({ list: [...(t?.list||[])], active: t?.active || null }));
905+
const newPanes = []; const newTabs = [];
906+
for (let r = 0; r < rows; r++) {
907+
for (let c = 0; c < oldCols; c++) {
908+
newPanes.push(oldPanes[r * oldCols + c]);
909+
newTabs.push(oldTabs[r * oldCols + c]);
910+
if (c === insertAfterCol) {
911+
newPanes.push(new ClaudePane(0, this.app));
912+
newTabs.push({ list: [], active: null });
900913
}
901914
}
902-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
903-
const target = row * this.cols + (col + 1); this.assignSession(target, sid);
904-
if (!copy) this.removeTabFromPane(index, sid);
905-
} else if (direction === 'top') {
906-
if ((this.rows + 1) * this.cols > this.maxPanes) return;
907-
if (this.rows === 1) { this.rows = 2; this.heights = [50, 50]; }
908-
const newPanes = []; const newTabs = [];
909-
for (let r = 0; r < this.rows; r++) {
910-
if (r === row) { for (let c = 0; c < this.cols; c++) { newPanes.push(new ClaudePane(newPanes.length, this.app)); newTabs.push({ list: [], active: null }); } }
911-
for (let c = 0; c < this.cols; c++) { const oldIdx = (r > row ? r - 1 : r) * this.cols + c; newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]); }
915+
}
916+
this.cols = oldCols + 1;
917+
this.widths = Array(this.cols).fill(100 / this.cols);
918+
this.panes = newPanes; this.tabs = newTabs;
919+
this.rebuildGrid();
920+
}
921+
922+
insertRow(insertAfterRow) {
923+
if (this.rows >= 2) return; // cap rows to 2
924+
const oldRows = this.rows; const cols = this.cols;
925+
const oldPanes = this.panes.slice(); const oldTabs = this.tabs.map(t => ({ list: [...(t?.list||[])], active: t?.active || null }));
926+
const newPanes = []; const newTabs = [];
927+
for (let r = 0; r < oldRows; r++) {
928+
for (let c = 0; c < cols; c++) {
929+
newPanes.push(oldPanes[r * cols + c]);
930+
newTabs.push(oldTabs[r * cols + c]);
912931
}
913-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
914-
const target = row * this.cols + col; this.assignSession(target, sid);
915-
if (!copy) this.removeTabFromPane(index + this.cols, sid);
916-
} else if (direction === 'bottom') {
917-
if ((this.rows + 1) * this.cols > this.maxPanes) return;
918-
if (this.rows === 1) { this.rows = 2; this.heights = [50, 50]; }
919-
const newPanes = []; const newTabs = [];
920-
for (let r = 0; r < this.rows; r++) {
921-
for (let c = 0; c < this.cols; c++) { const oldIdx = r * this.cols + c; newPanes.push(this.panes[oldIdx]); newTabs.push(this.tabs[oldIdx]); }
922-
if (r === row) { for (let c = 0; c < this.cols; c++) { newPanes.push(new ClaudePane(newPanes.length, this.app)); newTabs.push({ list: [], active: null }); } }
932+
if (r === insertAfterRow) {
933+
for (let c = 0; c < cols; c++) { newPanes.push(new ClaudePane(0, this.app)); newTabs.push({ list: [], active: null }); }
923934
}
924-
this.panes = newPanes; this.tabs = newTabs; this.rebuildGrid();
925-
const target = (row + 1) * this.cols + col; this.assignSession(target, sid);
926-
if (!copy) this.removeTabFromPane(index, sid);
927935
}
936+
this.rows = oldRows + 1;
937+
this.heights = this.rows === 2 ? [50, 50] : [100];
938+
this.panes = newPanes; this.tabs = newTabs;
939+
this.rebuildGrid();
928940
}
929941

930942
openAddMenu(index, anchorEl) {

0 commit comments

Comments
 (0)