From b3fe4dd2cdac911ee5375ec175a5f25145e17c84 Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Tue, 2 Sep 2025 16:02:46 +0300 Subject: [PATCH] feat: add multi-line command support for tmux panes - Refactor `send_command` to handle multi-line input - Implement `send_multiline_command` to execute temp scripts - Create temporary bash scripts for multi-line commands - Add documentation and examples for multi-line commands --- .../multiline_commands_demo.heroscript | 74 +++++++++++++++++++ lib/osal/tmux/readme.md | 53 +++++++++++++ lib/osal/tmux/tmux_pane.v | 45 ++++++++++- 3 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 examples/osal/tmux/heroscripts/multiline_commands_demo.heroscript diff --git a/examples/osal/tmux/heroscripts/multiline_commands_demo.heroscript b/examples/osal/tmux/heroscripts/multiline_commands_demo.heroscript new file mode 100644 index 00000000..dfb912c0 --- /dev/null +++ b/examples/osal/tmux/heroscripts/multiline_commands_demo.heroscript @@ -0,0 +1,74 @@ +#!/usr/bin/env hero + +// Demonstration of multi-line command support in tmux heroscripts +// This example shows how to use multi-line commands in pane configurations + +// Create a development session +!!tmux.session_create + name:"dev_multiline" + reset:true + +// Create a 4-pane development workspace +!!tmux.window_ensure + name:"dev_multiline|workspace" + cat:"4pane" + +// Pane 1: Development environment setup +!!tmux.pane_ensure + name:"dev_multiline|workspace|1" + label:"dev_setup" + cmd:' + echo "=== Development Environment Setup ===" + echo "Current directory: $(pwd)" + echo "Git status:" + git status --porcelain || echo "Not a git repository" + echo "Available disk space:" + df -h . + echo "Development setup complete" + ' + +// Pane 2: System monitoring +!!tmux.pane_ensure + name:"dev_multiline|workspace|2" + label:"monitoring" + cmd:' + echo "=== System Monitoring ===" + echo "System uptime:" + uptime + echo "Memory usage:" + free -h 2>/dev/null || vm_stat | head -5 + echo "CPU info:" + sysctl -n machdep.cpu.brand_string 2>/dev/null || cat /proc/cpuinfo | grep "model name" | head -1 + echo "Monitoring setup complete" + ' + +// Pane 3: Network diagnostics +!!tmux.pane_ensure + name:"dev_multiline|workspace|3" + label:"network" + cmd:' + echo "=== Network Diagnostics ===" + echo "Network interfaces:" + ifconfig | grep -E "^[a-z]|inet " | head -10 + echo "DNS configuration:" + cat /etc/resolv.conf 2>/dev/null || scutil --dns | head -10 + echo "Network diagnostics complete" + ' + +// Pane 4: File operations and cleanup +!!tmux.pane_ensure + name:"dev_multiline|workspace|4" + label:"file_ops" + cmd:' + echo "=== File Operations ===" + echo "Creating temporary workspace..." + mkdir -p /tmp/dev_workspace + cd /tmp/dev_workspace + echo "Current location: $(pwd)" + echo "Creating sample files..." + echo "Sample content" > sample.txt + echo "Another file" > another.txt + echo "Files created:" + ls -la + echo "File operations complete" + ' diff --git a/lib/osal/tmux/readme.md b/lib/osal/tmux/readme.md index 4649ef38..79d1ee41 100644 --- a/lib/osal/tmux/readme.md +++ b/lib/osal/tmux/readme.md @@ -164,6 +164,59 @@ hero run -p label:'editor' // Optional: descriptive label cmd:'vim' // Optional: command to run env:'EDITOR=vim' // Optional: environment variables + +// Multi-line commands are supported using proper heroscript syntax +!!tmux.pane_ensure + name:"mysession|mywindow|2" + label:'setup' + cmd:' + echo "Starting setup..." + mkdir -p /tmp/workspace + cd /tmp/workspace + echo "Setup complete" + ' +``` + +### Multi-line Commands + +The tmux module supports multi-line commands in heroscripts using proper multi-line parameter syntax. Multi-line commands are automatically converted to temporary shell scripts for execution. + +#### Syntax + +Use the multi-line parameter format with quotes: + +```heroscript +!!tmux.pane_ensure + name:"session|window|pane" + cmd:' + command1 + command2 + command3 + ' +``` + +#### Features + +- **Automatic Script Generation**: Multi-line commands are converted to temporary shell scripts +- **Sequential Execution**: All commands execute in order within the same shell context +- **Error Handling**: Scripts include proper bash shebang and error handling +- **Temporary Files**: Scripts are stored in `/tmp/tmux/{session}/pane_{id}_script.sh` + +#### Example + +```heroscript +!!tmux.pane_ensure + name:"dev|workspace|1" + label:"setup" + cmd:' + echo "Setting up development environment..." + mkdir -p /tmp/dev_workspace + cd /tmp/dev_workspace + git clone https://github.com/example/repo.git + cd repo + npm install + echo "Development environment ready!" + ' ``` ### Pane Layout Categories diff --git a/lib/osal/tmux/tmux_pane.v b/lib/osal/tmux/tmux_pane.v index a30e3c96..1e43f8b1 100644 --- a/lib/osal/tmux/tmux_pane.v +++ b/lib/osal/tmux/tmux_pane.v @@ -146,9 +146,50 @@ pub fn (mut p Pane) processinfo_main() !osal.ProcessInfo { } // Send a command to this pane +// Supports both single-line and multi-line commands pub fn (mut p Pane) send_command(command string) ! { - cmd := 'tmux send-keys -t ${p.window.session.name}:@${p.window.id}.%${p.id} "${command}" Enter' - osal.execute_silent(cmd) or { return error('Cannot send command to pane %${p.id}: ${err}') } + // Check if command contains multiple lines + if command.contains('\n') { + // Multi-line command - create temporary script + p.send_multiline_command(command)! + } else { + // Single-line command - send directly + cmd := 'tmux send-keys -t ${p.window.session.name}:@${p.window.id}.%${p.id} "${command}" Enter' + osal.execute_silent(cmd) or { return error('Cannot send command to pane %${p.id}: ${err}') } + } +} + +// Handle multi-line commands by creating a temporary script +fn (mut p Pane) send_multiline_command(command string) ! { + // Create temporary directory for tmux scripts + script_dir := '/tmp/tmux/${p.window.session.name}' + os.mkdir_all(script_dir) or { return error('Cannot create script directory: ${err}') } + + // Create unique script file for this pane + script_path := '${script_dir}/pane_${p.id}_script.sh' + + // Prepare script content with proper shebang and commands + script_content := '#!/bin/bash\n' + command.trim_space() + + // Write script to file + os.write_file(script_path, script_content) or { + return error('Cannot write script file ${script_path}: ${err}') + } + + // Make script executable + os.chmod(script_path, 0o755) or { + return error('Cannot make script executable ${script_path}: ${err}') + } + + // Execute the script in the pane + cmd := 'tmux send-keys -t ${p.window.session.name}:@${p.window.id}.%${p.id} "${script_path}" Enter' + osal.execute_silent(cmd) or { return error('Cannot execute script in pane %${p.id}: ${err}') } + + // Optional: Clean up script after a delay (commented out for debugging) + // spawn { + // time.sleep(5 * time.second) + // os.rm(script_path) or {} + // } } // Send raw keys to this pane (without Enter)