diff --git a/README.md b/README.md index 0e86afa..6e5116c 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,11 @@ tx create -S # save only (don't create) tx prj [name] tx prj -s # save to config +# Create session in background (don't switch to it) +tx -b my-session +tx create -b +tx prj -b myproject + # Attach to existing session tx attach [name] @@ -98,10 +103,11 @@ tx kill foo bar baz # kill multiple sessions ### Global Flags -| Flag | Description | -| --------------- | ----------------------------------------- | -| `-v, --verbose` | Verbose logging | -| `-d, --dry` | Dry run (show commands without executing) | +| Flag | Description | +| ------------------ | ---------------------------------------------------- | +| `-V, --verbose` | Verbose logging | +| `-d, --dry` | Dry run (show commands without executing) | +| `-b, --background` | Create session in background without switching to it | --- @@ -275,11 +281,11 @@ layout: #### Split Options -| Setting | Description | -| ----------- | ------------------------------------------------------ | +| Setting | Description | +| ----------- | ----------------------------------------------------------- | | `direction` | `h` (horizontal / side-by-side) or `v` (vertical / stacked) | -| `size` | Percentage of space for the child pane (1-100, default: 50) | -| `child` | Pane configuration for the new pane created by the split | +| `size` | Percentage of space for the child pane (1-100, default: 50) | +| `child` | Pane configuration for the new pane created by the split | ### Global Settings @@ -308,8 +314,8 @@ myproject: #### Default Layout -The `default_layout` setting overrides the built-in default pane arrangement for all windows. -It accepts the same [pane options](#pane-options) as a regular layout. +The `default_layout` setting overrides the built-in default pane arrangement for all windows. It +accepts the same [pane options](#pane-options) as a regular layout. ```yaml .config: @@ -446,6 +452,9 @@ tx create -r ~/myproject -w src -w lib -w test # Create and save to config tx create -r ~/myproject -s + +# Create in background (don't switch to it) +tx create -b -r ~/myproject ``` ### Project Workflow diff --git a/internal/cli/create_cmd.go b/internal/cli/create_cmd.go index afb8927..4dc78b8 100644 --- a/internal/cli/create_cmd.go +++ b/internal/cli/create_cmd.go @@ -75,6 +75,10 @@ func runCreate(cmd *cobra.Command, args []string) error { // Check if session exists if tmux.SessionExists(opts, parsed.Name) { + if background { + exec.Log(opts, "Session already exists (background mode, not attaching)") + return nil + } exec.Log(opts, "Session already exists, attaching") return tmux.AttachToSession(opts, parsed.Name) } @@ -92,5 +96,5 @@ func runCreate(cmd *cobra.Command, args []string) error { } // Create the session - return tmux.CreateFromConfig(opts, parsed) + return tmux.CreateFromConfig(opts, parsed, background) } diff --git a/internal/cli/main_cmd.go b/internal/cli/main_cmd.go index a405364..217fb32 100644 --- a/internal/cli/main_cmd.go +++ b/internal/cli/main_cmd.go @@ -53,10 +53,14 @@ func runMain(cmd *cobra.Command, args []string) error { // Check if session exists if tmux.SessionExists(opts, parsed.Name) { + if background { + exec.Log(opts, "Session exists (background mode, not attaching)") + return nil + } exec.Log(opts, "Session exists, attaching...") return tmux.AttachToSession(opts, parsed.Name) } // Create session - return tmux.CreateFromConfig(opts, parsed) + return tmux.CreateFromConfig(opts, parsed, background) } diff --git a/internal/cli/prj_cmd.go b/internal/cli/prj_cmd.go index 9d4d63f..0bb0c9f 100644 --- a/internal/cli/prj_cmd.go +++ b/internal/cli/prj_cmd.go @@ -119,7 +119,7 @@ func runPrj(cmd *cobra.Command, args []string) error { } // Create session - return tmux.CreateFromConfig(opts, parsed) + return tmux.CreateFromConfig(opts, parsed, background) } // getProjects returns directory names in the given path diff --git a/internal/cli/root.go b/internal/cli/root.go index 946751b..cce2dc3 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -16,8 +16,9 @@ var ( Version string // Global flags - verbose bool - dry bool + verbose bool + dry bool + background bool ) // GetOpts returns the current execution options @@ -166,6 +167,7 @@ func init() { // Global flags rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "V", false, "Verbose logging") rootCmd.PersistentFlags().BoolVarP(&dry, "dry", "d", false, "Dry run (log commands, don't execute)") + rootCmd.PersistentFlags().BoolVarP(&background, "background", "b", false, "Create session in background without attaching") rootCmd.Flags().BoolP("version", "v", false, "Print version") // Add subcommands diff --git a/internal/tmux/builder.go b/internal/tmux/builder.go index 25fc1ee..dbd3a3b 100644 --- a/internal/tmux/builder.go +++ b/internal/tmux/builder.go @@ -8,8 +8,9 @@ import ( "github.com/chenasraf/tx/internal/exec" ) -// CreateFromConfig creates a tmux session from a parsed config -func CreateFromConfig(opts exec.Opts, tmuxConfig config.ParsedTmuxConfigItem) error { +// CreateFromConfig creates a tmux session from a parsed config. +// If background is true, the session is created but not attached to. +func CreateFromConfig(opts exec.Opts, tmuxConfig config.ParsedTmuxConfigItem, background bool) error { root := tmuxConfig.Root windows := tmuxConfig.Windows sessionName := config.NameFix(tmuxConfig.Name) @@ -19,6 +20,10 @@ func CreateFromConfig(opts exec.Opts, tmuxConfig config.ParsedTmuxConfigItem) er // Check if session already exists if SessionExists(opts, sessionName) { + if background { + exec.Log(opts, fmt.Sprintf("tmux session %s already exists (background mode, not attaching)", sessionName)) + return nil + } exec.Log(opts, fmt.Sprintf("tmux session %s already exists, attaching...", sessionName)) return AttachToSession(opts, sessionName) } @@ -73,7 +78,10 @@ func CreateFromConfig(opts exec.Opts, tmuxConfig config.ParsedTmuxConfigItem) er } } - // Attach to the session + // Attach to the session unless background mode + if background { + return nil + } return AttachToSession(opts, sessionName) } diff --git a/internal/tmux/builder_test.go b/internal/tmux/builder_test.go index 9b29fdf..216ea04 100644 --- a/internal/tmux/builder_test.go +++ b/internal/tmux/builder_test.go @@ -251,7 +251,7 @@ func TestCreateFromConfig_DryRun(t *testing.T) { } // In dry mode, this should succeed without actually running tmux - err := CreateFromConfig(opts, tmuxConfig) + err := CreateFromConfig(opts, tmuxConfig, false) if err != nil { t.Errorf("expected no error in dry mode, got %v", err) } @@ -281,7 +281,7 @@ func TestCreateFromConfig_MultipleWindows(t *testing.T) { }, } - err := CreateFromConfig(opts, tmuxConfig) + err := CreateFromConfig(opts, tmuxConfig, false) if err != nil { t.Errorf("expected no error in dry mode, got %v", err) }