This commit is contained in:
150
src/commands/save.ts
Normal file
150
src/commands/save.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import inquirer from 'inquirer';
|
||||
import { fileUtils } from '../utils/fileUtils';
|
||||
import { tmuxParser, screenParser, iterm2Parser } from '../parsers';
|
||||
import { Layout, TerminalType } from '../models/types';
|
||||
|
||||
interface SaveOptions {
|
||||
name?: string;
|
||||
terminal?: TerminalType;
|
||||
session?: string;
|
||||
format?: 'json' | 'yaml';
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export async function saveLayout(options: SaveOptions): Promise<void> {
|
||||
await fileUtils.initialize();
|
||||
|
||||
let terminalType = options.terminal;
|
||||
if (!terminalType) {
|
||||
const availableTerminals = await detectAvailableTerminals();
|
||||
if (availableTerminals.length === 0) {
|
||||
console.log('No supported terminal multiplexers found. Creating a manual layout.');
|
||||
terminalType = 'unknown';
|
||||
} else {
|
||||
const { selectedTerminal } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'selectedTerminal',
|
||||
message: 'Which terminal type would you like to save?',
|
||||
choices: availableTerminals.map((t) => ({ name: t, value: t })),
|
||||
},
|
||||
]);
|
||||
terminalType = selectedTerminal;
|
||||
}
|
||||
}
|
||||
|
||||
let layout: Layout;
|
||||
|
||||
switch (terminalType) {
|
||||
case 'tmux': {
|
||||
const sessionName = options.session || (await getDefaultSessionName('tmux'));
|
||||
const result = await tmuxParser.captureSession(sessionName);
|
||||
if (!result.success) {
|
||||
throw new Error(`Failed to capture tmux session: ${result.error}`);
|
||||
}
|
||||
layout = result.data!;
|
||||
break;
|
||||
}
|
||||
case 'screen': {
|
||||
const sessionName = options.session || (await getDefaultSessionName('screen'));
|
||||
const result = await screenParser.captureSession(sessionName);
|
||||
if (!result.success) {
|
||||
throw new Error(`Failed to capture screen session: ${result.error}`);
|
||||
}
|
||||
layout = result.data!;
|
||||
break;
|
||||
}
|
||||
case 'iterm2': {
|
||||
const result = await iterm2Parser.captureCurrentLayout();
|
||||
if (!result.success) {
|
||||
throw new Error(`Failed to capture iTerm2 layout: ${result.error}`);
|
||||
}
|
||||
layout = result.data!;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
layout = createEmptyLayout('unknown');
|
||||
}
|
||||
|
||||
let layoutName = options.name;
|
||||
if (!layoutName) {
|
||||
const { name } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Enter a name for this layout:',
|
||||
validate: (input: string) => input.trim() !== '' || 'Name cannot be empty',
|
||||
},
|
||||
]);
|
||||
layoutName = name;
|
||||
}
|
||||
|
||||
layout.metadata = layout.metadata || {};
|
||||
if (options.description) {
|
||||
layout.metadata.description = options.description;
|
||||
} else {
|
||||
const { description } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'description',
|
||||
message: 'Enter a description (optional):',
|
||||
default: '',
|
||||
},
|
||||
]);
|
||||
if (description) {
|
||||
layout.metadata.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
const finalName = layoutName || 'untitled-layout';
|
||||
const format = options.format || 'json';
|
||||
const filePath = await fileUtils.saveLayout(finalName, layout, format);
|
||||
console.log(`Layout saved to: ${filePath}`);
|
||||
}
|
||||
|
||||
async function detectAvailableTerminals(): Promise<TerminalType[]> {
|
||||
const terminals: TerminalType[] = [];
|
||||
|
||||
const [tmuxAvailable, screenAvailable, iterm2Available] = await Promise.all([
|
||||
tmuxParser.isAvailable(),
|
||||
screenParser.isAvailable(),
|
||||
iterm2Parser.isAvailable(),
|
||||
]);
|
||||
|
||||
if (tmuxAvailable) terminals.push('tmux');
|
||||
if (screenAvailable) terminals.push('screen');
|
||||
if (iterm2Available) terminals.push('iterm2');
|
||||
|
||||
return terminals;
|
||||
}
|
||||
|
||||
async function getDefaultSessionName(terminal: string): Promise<string | undefined> {
|
||||
if (terminal === 'tmux') {
|
||||
const sessions = await tmuxParser.listSessions();
|
||||
if (sessions.length === 0) {
|
||||
console.log('No tmux sessions found. Please specify a session name.');
|
||||
return undefined;
|
||||
}
|
||||
return sessions[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createEmptyLayout(terminalType: TerminalType): Layout {
|
||||
return {
|
||||
version: '1.0.0',
|
||||
terminalType,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
session: {
|
||||
id: 's-manual',
|
||||
name: 'manual',
|
||||
windows: [],
|
||||
activeWindowIndex: 0,
|
||||
},
|
||||
metadata: {
|
||||
description: 'Manually created layout',
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user