@jx0/jmux 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/__tests__/sidebar.test.ts +121 -0
- package/src/input-router.ts +7 -0
- package/src/main.ts +6 -1
- package/src/sidebar.ts +150 -125
package/package.json
CHANGED
|
@@ -235,4 +235,125 @@ describe("Sidebar", () => {
|
|
|
235
235
|
}
|
|
236
236
|
expect(found).toBe(true);
|
|
237
237
|
});
|
|
238
|
+
|
|
239
|
+
test("scrolls to show active session when it overflows", () => {
|
|
240
|
+
// Height 10 = 2 header rows + 8 viewport rows
|
|
241
|
+
// Each session = 2 rows + 1 spacer = 3 rows, so 8 rows fits ~2.6 sessions
|
|
242
|
+
const sidebar = new Sidebar(SIDEBAR_WIDTH, 10);
|
|
243
|
+
sidebar.updateSessions(
|
|
244
|
+
makeSessions([
|
|
245
|
+
{ name: "a" },
|
|
246
|
+
{ name: "b" },
|
|
247
|
+
{ name: "c" },
|
|
248
|
+
{ name: "d" },
|
|
249
|
+
]),
|
|
250
|
+
);
|
|
251
|
+
// Activate last session and scroll to it
|
|
252
|
+
sidebar.setActiveSession("$3");
|
|
253
|
+
sidebar.scrollToActive();
|
|
254
|
+
const grid = sidebar.getGrid();
|
|
255
|
+
// "d" should be visible somewhere in the grid
|
|
256
|
+
let found = false;
|
|
257
|
+
for (let r = 2; r < 10; r++) {
|
|
258
|
+
const text = Array.from(
|
|
259
|
+
{ length: SIDEBAR_WIDTH },
|
|
260
|
+
(_, i) => grid.cells[r][i].char,
|
|
261
|
+
).join("");
|
|
262
|
+
if (text.includes("d")) {
|
|
263
|
+
found = true;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
expect(found).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("scrollBy moves viewport and clamps to bounds", () => {
|
|
271
|
+
const sidebar = new Sidebar(SIDEBAR_WIDTH, 10);
|
|
272
|
+
sidebar.updateSessions(
|
|
273
|
+
makeSessions([
|
|
274
|
+
{ name: "a" },
|
|
275
|
+
{ name: "b" },
|
|
276
|
+
{ name: "c" },
|
|
277
|
+
{ name: "d" },
|
|
278
|
+
]),
|
|
279
|
+
);
|
|
280
|
+
// First session visible at start
|
|
281
|
+
let grid = sidebar.getGrid();
|
|
282
|
+
const row2 = Array.from(
|
|
283
|
+
{ length: SIDEBAR_WIDTH },
|
|
284
|
+
(_, i) => grid.cells[2][i].char,
|
|
285
|
+
).join("");
|
|
286
|
+
expect(row2).toContain("a");
|
|
287
|
+
|
|
288
|
+
// Scroll down
|
|
289
|
+
sidebar.scrollBy(3);
|
|
290
|
+
grid = sidebar.getGrid();
|
|
291
|
+
// "a" should no longer be on row 2
|
|
292
|
+
const row2After = Array.from(
|
|
293
|
+
{ length: SIDEBAR_WIDTH },
|
|
294
|
+
(_, i) => grid.cells[2][i].char,
|
|
295
|
+
).join("");
|
|
296
|
+
expect(row2After).not.toContain("a");
|
|
297
|
+
|
|
298
|
+
// Scroll way past the top — should clamp to 0
|
|
299
|
+
sidebar.scrollBy(-100);
|
|
300
|
+
grid = sidebar.getGrid();
|
|
301
|
+
const row2Reset = Array.from(
|
|
302
|
+
{ length: SIDEBAR_WIDTH },
|
|
303
|
+
(_, i) => grid.cells[2][i].char,
|
|
304
|
+
).join("");
|
|
305
|
+
expect(row2Reset).toContain("a");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("shows scroll indicators when content overflows", () => {
|
|
309
|
+
const sidebar = new Sidebar(SIDEBAR_WIDTH, 10);
|
|
310
|
+
sidebar.updateSessions(
|
|
311
|
+
makeSessions([
|
|
312
|
+
{ name: "a" },
|
|
313
|
+
{ name: "b" },
|
|
314
|
+
{ name: "c" },
|
|
315
|
+
{ name: "d" },
|
|
316
|
+
]),
|
|
317
|
+
);
|
|
318
|
+
// At top: should show down indicator but not up
|
|
319
|
+
let grid = sidebar.getGrid();
|
|
320
|
+
expect(grid.cells[2][SIDEBAR_WIDTH - 1].char).not.toBe("\u25b2");
|
|
321
|
+
expect(grid.cells[9][SIDEBAR_WIDTH - 1].char).toBe("\u25bc");
|
|
322
|
+
|
|
323
|
+
// Scroll to middle: should show both
|
|
324
|
+
sidebar.scrollBy(3);
|
|
325
|
+
grid = sidebar.getGrid();
|
|
326
|
+
expect(grid.cells[2][SIDEBAR_WIDTH - 1].char).toBe("\u25b2");
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("scrollToActive snaps back after manual scroll", () => {
|
|
330
|
+
const sidebar = new Sidebar(SIDEBAR_WIDTH, 10);
|
|
331
|
+
sidebar.updateSessions(
|
|
332
|
+
makeSessions([
|
|
333
|
+
{ name: "a" },
|
|
334
|
+
{ name: "b" },
|
|
335
|
+
{ name: "c" },
|
|
336
|
+
{ name: "d" },
|
|
337
|
+
]),
|
|
338
|
+
);
|
|
339
|
+
sidebar.setActiveSession("$0"); // "a" is active
|
|
340
|
+
// Scroll away from active session
|
|
341
|
+
sidebar.scrollBy(6);
|
|
342
|
+
// Snap back
|
|
343
|
+
sidebar.scrollToActive();
|
|
344
|
+
const grid = sidebar.getGrid();
|
|
345
|
+
// "a" should be visible
|
|
346
|
+
let found = false;
|
|
347
|
+
for (let r = 2; r < 10; r++) {
|
|
348
|
+
const text = Array.from(
|
|
349
|
+
{ length: SIDEBAR_WIDTH },
|
|
350
|
+
(_, i) => grid.cells[r][i].char,
|
|
351
|
+
).join("");
|
|
352
|
+
if (text.includes("a")) {
|
|
353
|
+
found = true;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
expect(found).toBe(true);
|
|
358
|
+
});
|
|
238
359
|
});
|
package/src/input-router.ts
CHANGED
|
@@ -33,6 +33,7 @@ export interface InputRouterOptions {
|
|
|
33
33
|
sidebarCols: number;
|
|
34
34
|
onPtyData: (data: string) => void;
|
|
35
35
|
onSidebarClick: (row: number) => void;
|
|
36
|
+
onSidebarScroll?: (delta: number) => void;
|
|
36
37
|
onSessionPrev?: () => void;
|
|
37
38
|
onSessionNext?: () => void;
|
|
38
39
|
}
|
|
@@ -65,6 +66,12 @@ export class InputRouter {
|
|
|
65
66
|
const mouse = parseSgrMouse(data);
|
|
66
67
|
if (mouse && this.sidebarVisible) {
|
|
67
68
|
if (mouse.x <= this.opts.sidebarCols) {
|
|
69
|
+
// Wheel events: button 64 = up, 65 = down
|
|
70
|
+
if ((mouse.button & 64) !== 0) {
|
|
71
|
+
const delta = (mouse.button & 1) ? 3 : -3;
|
|
72
|
+
this.opts.onSidebarScroll?.(delta);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
68
75
|
// Click in sidebar region (ignore drags — button bit 5 = motion)
|
|
69
76
|
if (!mouse.release && (mouse.button & 32) === 0) {
|
|
70
77
|
this.opts.onSidebarClick(mouse.y - 1); // 0-indexed row
|
package/src/main.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { homedir } from "os";
|
|
|
12
12
|
|
|
13
13
|
// --- CLI commands (run and exit before TUI) ---
|
|
14
14
|
|
|
15
|
-
const VERSION = "0.3.
|
|
15
|
+
const VERSION = "0.3.4";
|
|
16
16
|
|
|
17
17
|
const HELP = `jmux — a persistent session sidebar for tmux
|
|
18
18
|
|
|
@@ -255,6 +255,7 @@ async function switchSession(sessionId: string): Promise<void> {
|
|
|
255
255
|
sidebar.setActivity(sessionId, false);
|
|
256
256
|
currentSessionId = sessionId;
|
|
257
257
|
sidebar.setActiveSession(sessionId);
|
|
258
|
+
sidebar.scrollToActive();
|
|
258
259
|
renderFrame();
|
|
259
260
|
|
|
260
261
|
// Clear attention flag if set
|
|
@@ -298,6 +299,10 @@ const inputRouter = new InputRouter(
|
|
|
298
299
|
const session = sidebar.getSessionByRow(row);
|
|
299
300
|
if (session) switchSession(session.id);
|
|
300
301
|
},
|
|
302
|
+
onSidebarScroll: (delta) => {
|
|
303
|
+
sidebar.scrollBy(delta);
|
|
304
|
+
scheduleRender();
|
|
305
|
+
},
|
|
301
306
|
onSessionPrev: () => switchByOffset(-1),
|
|
302
307
|
onSessionNext: () => switchByOffset(1),
|
|
303
308
|
},
|
package/src/sidebar.ts
CHANGED
|
@@ -145,6 +145,10 @@ function buildRenderPlan(sessions: SessionInfo[]): {
|
|
|
145
145
|
return { items, displayOrder };
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
function itemHeight(item: RenderItem): number {
|
|
149
|
+
return item.type === "session" ? 2 : 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
// --- Sidebar class ---
|
|
149
153
|
|
|
150
154
|
export class Sidebar {
|
|
@@ -152,9 +156,11 @@ export class Sidebar {
|
|
|
152
156
|
private height: number;
|
|
153
157
|
private sessions: SessionInfo[] = [];
|
|
154
158
|
private activeSessionId: string | null = null;
|
|
159
|
+
private items: RenderItem[] = [];
|
|
155
160
|
private displayOrder: number[] = [];
|
|
156
161
|
private rowToSessionIndex = new Map<number, number>();
|
|
157
162
|
private activitySet = new Set<string>();
|
|
163
|
+
private scrollOffset = 0;
|
|
158
164
|
|
|
159
165
|
constructor(width: number, height: number) {
|
|
160
166
|
this.width = width;
|
|
@@ -163,8 +169,10 @@ export class Sidebar {
|
|
|
163
169
|
|
|
164
170
|
updateSessions(sessions: SessionInfo[]): void {
|
|
165
171
|
this.sessions = sessions;
|
|
166
|
-
const { displayOrder } = buildRenderPlan(sessions);
|
|
172
|
+
const { items, displayOrder } = buildRenderPlan(sessions);
|
|
173
|
+
this.items = items;
|
|
167
174
|
this.displayOrder = displayOrder;
|
|
175
|
+
this.clampScroll();
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
setActiveSession(id: string): void {
|
|
@@ -194,6 +202,41 @@ export class Sidebar {
|
|
|
194
202
|
resize(width: number, height: number): void {
|
|
195
203
|
this.width = width;
|
|
196
204
|
this.height = height;
|
|
205
|
+
this.clampScroll();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
scrollBy(delta: number): void {
|
|
209
|
+
this.scrollOffset += delta;
|
|
210
|
+
this.clampScroll();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
scrollToActive(): void {
|
|
214
|
+
if (!this.activeSessionId) return;
|
|
215
|
+
const viewportHeight = this.height - HEADER_ROWS;
|
|
216
|
+
let vRow = 0;
|
|
217
|
+
for (const item of this.items) {
|
|
218
|
+
const h = itemHeight(item);
|
|
219
|
+
if (item.type === "session") {
|
|
220
|
+
const session = this.sessions[item.sessionIndex];
|
|
221
|
+
if (session?.id === this.activeSessionId) {
|
|
222
|
+
if (vRow < this.scrollOffset) {
|
|
223
|
+
this.scrollOffset = vRow;
|
|
224
|
+
} else if (vRow + h > this.scrollOffset + viewportHeight) {
|
|
225
|
+
this.scrollOffset = vRow + h - viewportHeight;
|
|
226
|
+
}
|
|
227
|
+
this.clampScroll();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
vRow += h;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private clampScroll(): void {
|
|
236
|
+
const totalRows = this.items.reduce((sum, item) => sum + itemHeight(item), 0);
|
|
237
|
+
const viewportHeight = this.height - HEADER_ROWS;
|
|
238
|
+
const maxOffset = Math.max(0, totalRows - viewportHeight);
|
|
239
|
+
this.scrollOffset = Math.max(0, Math.min(maxOffset, this.scrollOffset));
|
|
197
240
|
}
|
|
198
241
|
|
|
199
242
|
getGrid(): CellGrid {
|
|
@@ -204,152 +247,134 @@ export class Sidebar {
|
|
|
204
247
|
writeString(grid, 0, 1, "jmux", { ...ACCENT_ATTRS, bold: true });
|
|
205
248
|
writeString(grid, 1, 0, "\u2500".repeat(this.width), DIM_ATTRS);
|
|
206
249
|
|
|
207
|
-
const
|
|
208
|
-
let
|
|
250
|
+
const viewportHeight = this.height - HEADER_ROWS;
|
|
251
|
+
let vRow = 0;
|
|
252
|
+
let totalRows = 0;
|
|
209
253
|
|
|
210
|
-
for (const item of items) {
|
|
211
|
-
|
|
254
|
+
for (const item of this.items) {
|
|
255
|
+
const h = itemHeight(item);
|
|
256
|
+
const screenRow = HEADER_ROWS + vRow - this.scrollOffset;
|
|
212
257
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
writeString(grid, row, 1, label, GROUP_HEADER_ATTRS);
|
|
219
|
-
row++;
|
|
258
|
+
// Skip items entirely above viewport
|
|
259
|
+
if (screenRow + h <= HEADER_ROWS) {
|
|
260
|
+
vRow += h;
|
|
261
|
+
totalRows += h;
|
|
220
262
|
continue;
|
|
221
263
|
}
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
|
|
264
|
+
// Track total rows even after viewport
|
|
265
|
+
if (screenRow >= this.height) {
|
|
266
|
+
vRow += h;
|
|
267
|
+
totalRows += h;
|
|
225
268
|
continue;
|
|
226
269
|
}
|
|
227
270
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const nameRow = row;
|
|
233
|
-
const isActive = session.id === this.activeSessionId;
|
|
234
|
-
const hasActivity = this.activitySet.has(session.id);
|
|
235
|
-
|
|
236
|
-
if (item.grouped) {
|
|
237
|
-
// Grouped: two rows — name + window count, then subdirectory + branch
|
|
238
|
-
const detailRow = row + 1;
|
|
239
|
-
|
|
240
|
-
this.rowToSessionIndex.set(nameRow, sessionIdx);
|
|
241
|
-
if (detailRow < this.height) {
|
|
242
|
-
this.rowToSessionIndex.set(detailRow, sessionIdx);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (isActive) {
|
|
246
|
-
writeString(grid, nameRow, 0, "\u258e", ACTIVE_MARKER_ATTRS);
|
|
247
|
-
if (detailRow < this.height) {
|
|
248
|
-
writeString(grid, detailRow, 0, "\u258e", ACTIVE_MARKER_ATTRS);
|
|
249
|
-
}
|
|
271
|
+
if (item.type === "group-header") {
|
|
272
|
+
let label = item.label;
|
|
273
|
+
if (label.length > this.width - 2) {
|
|
274
|
+
label = label.slice(0, this.width - 3) + "\u2026";
|
|
250
275
|
}
|
|
276
|
+
writeString(grid, screenRow, 1, label, GROUP_HEADER_ATTRS);
|
|
277
|
+
} else if (item.type === "spacer") {
|
|
278
|
+
// nothing to render
|
|
279
|
+
} else {
|
|
280
|
+
this.renderSession(grid, screenRow, item);
|
|
281
|
+
}
|
|
251
282
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
writeString(grid, nameRow, 1, "\u25CF", ACTIVITY_ATTRS);
|
|
256
|
-
}
|
|
283
|
+
vRow += h;
|
|
284
|
+
totalRows += h;
|
|
285
|
+
}
|
|
257
286
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
287
|
+
// Scroll indicators
|
|
288
|
+
if (this.scrollOffset > 0) {
|
|
289
|
+
writeString(grid, HEADER_ROWS, this.width - 1, "\u25b2", DIM_ATTRS);
|
|
290
|
+
}
|
|
291
|
+
if (this.scrollOffset + viewportHeight < totalRows) {
|
|
292
|
+
writeString(grid, this.height - 1, this.width - 1, "\u25bc", DIM_ATTRS);
|
|
293
|
+
}
|
|
266
294
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
: { ...INACTIVE_NAME_ATTRS };
|
|
270
|
-
writeString(grid, nameRow, nameStart, displayName, nameAttrs);
|
|
295
|
+
return grid;
|
|
296
|
+
}
|
|
271
297
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
298
|
+
private renderSession(
|
|
299
|
+
grid: CellGrid,
|
|
300
|
+
nameRow: number,
|
|
301
|
+
item: Extract<RenderItem, { type: "session" }>,
|
|
302
|
+
): void {
|
|
303
|
+
const sessionIdx = item.sessionIndex;
|
|
304
|
+
const session = this.sessions[sessionIdx];
|
|
305
|
+
if (!session) return;
|
|
306
|
+
|
|
307
|
+
const detailRow = nameRow + 1;
|
|
308
|
+
const isActive = session.id === this.activeSessionId;
|
|
309
|
+
const hasActivity = this.activitySet.has(session.id);
|
|
310
|
+
|
|
311
|
+
// Map rows to session for click handling
|
|
312
|
+
this.rowToSessionIndex.set(nameRow, sessionIdx);
|
|
313
|
+
if (detailRow < this.height) {
|
|
314
|
+
this.rowToSessionIndex.set(detailRow, sessionIdx);
|
|
315
|
+
}
|
|
275
316
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (branch.length > maxLen) {
|
|
282
|
-
branch = branch.slice(0, maxLen - 1) + "\u2026";
|
|
283
|
-
}
|
|
284
|
-
writeString(grid, detailRow, detailStart, branch, DIM_ATTRS);
|
|
285
|
-
}
|
|
317
|
+
// Active marker
|
|
318
|
+
if (isActive) {
|
|
319
|
+
writeString(grid, nameRow, 0, "\u258e", ACTIVE_MARKER_ATTRS);
|
|
320
|
+
writeString(grid, detailRow, 0, "\u258e", ACTIVE_MARKER_ATTRS);
|
|
321
|
+
}
|
|
286
322
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
323
|
+
// Indicator
|
|
324
|
+
if (session.attention) {
|
|
325
|
+
writeString(grid, nameRow, 1, "!", ATTENTION_ATTRS);
|
|
326
|
+
} else if (hasActivity) {
|
|
327
|
+
writeString(grid, nameRow, 1, "\u25CF", ACTIVITY_ATTRS);
|
|
328
|
+
}
|
|
291
329
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
330
|
+
// Name row: name + window count
|
|
331
|
+
const windowCountStr = `${session.windowCount}w`;
|
|
332
|
+
const windowCountCol = this.width - windowCountStr.length - 1;
|
|
333
|
+
const nameStart = 3;
|
|
334
|
+
const nameMaxLen = windowCountCol - 1 - nameStart;
|
|
335
|
+
let displayName = session.name;
|
|
336
|
+
if (displayName.length > nameMaxLen) {
|
|
337
|
+
displayName = displayName.slice(0, nameMaxLen - 1) + "\u2026";
|
|
338
|
+
}
|
|
296
339
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
}
|
|
340
|
+
const nameAttrs: CellAttrs = isActive
|
|
341
|
+
? { ...ACTIVE_NAME_ATTRS }
|
|
342
|
+
: { ...INACTIVE_NAME_ATTRS };
|
|
343
|
+
writeString(grid, nameRow, nameStart, displayName, nameAttrs);
|
|
303
344
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
writeString(grid, nameRow, 1, "\u25CF", ACTIVITY_ATTRS);
|
|
308
|
-
}
|
|
345
|
+
if (windowCountCol > nameStart) {
|
|
346
|
+
writeString(grid, nameRow, windowCountCol, windowCountStr, DIM_ATTRS);
|
|
347
|
+
}
|
|
309
348
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
349
|
+
// Detail line
|
|
350
|
+
if (item.grouped) {
|
|
351
|
+
if (session.gitBranch) {
|
|
352
|
+
const detailStart = 3;
|
|
353
|
+
const maxLen = this.width - detailStart - 1;
|
|
354
|
+
let branch = session.gitBranch;
|
|
355
|
+
if (branch.length > maxLen) {
|
|
356
|
+
branch = branch.slice(0, maxLen - 1) + "\u2026";
|
|
317
357
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
358
|
+
writeString(grid, detailRow, detailStart, branch, DIM_ATTRS);
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
const detailStart = 3;
|
|
362
|
+
let branchCols = 0;
|
|
363
|
+
if (session.gitBranch) {
|
|
364
|
+
const branchCol = this.width - session.gitBranch.length - 1;
|
|
365
|
+
if (branchCol > detailStart + 1) {
|
|
366
|
+
writeString(grid, detailRow, branchCol, session.gitBranch, DIM_ATTRS);
|
|
367
|
+
branchCols = session.gitBranch.length + 2;
|
|
326
368
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const branchCol = this.width - session.gitBranch.length - 1;
|
|
334
|
-
if (branchCol > detailStart + 1) {
|
|
335
|
-
writeString(grid, detailRow, branchCol, session.gitBranch, DIM_ATTRS);
|
|
336
|
-
branchCols = session.gitBranch.length + 2;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
if (session.directory !== undefined) {
|
|
340
|
-
const dirMaxLen = this.width - detailStart - branchCols - 1;
|
|
341
|
-
let displayDir = session.directory;
|
|
342
|
-
if (displayDir.length > dirMaxLen) {
|
|
343
|
-
displayDir = displayDir.slice(0, dirMaxLen - 1) + "\u2026";
|
|
344
|
-
}
|
|
345
|
-
writeString(grid, detailRow, detailStart, displayDir, DIM_ATTRS);
|
|
346
|
-
}
|
|
369
|
+
}
|
|
370
|
+
if (session.directory !== undefined) {
|
|
371
|
+
const dirMaxLen = this.width - detailStart - branchCols - 1;
|
|
372
|
+
let displayDir = session.directory;
|
|
373
|
+
if (displayDir.length > dirMaxLen) {
|
|
374
|
+
displayDir = displayDir.slice(0, dirMaxLen - 1) + "\u2026";
|
|
347
375
|
}
|
|
348
|
-
|
|
349
|
-
row += 2;
|
|
376
|
+
writeString(grid, detailRow, detailStart, displayDir, DIM_ATTRS);
|
|
350
377
|
}
|
|
351
378
|
}
|
|
352
|
-
|
|
353
|
-
return grid;
|
|
354
379
|
}
|
|
355
380
|
}
|