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