diff --git a/src/commands/save.ts b/src/commands/save.ts new file mode 100644 index 0000000..3a38a9f --- /dev/null +++ b/src/commands/save.ts @@ -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 { + 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 { + 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 { + 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', + }, + }; +}