4 Commits

Author SHA1 Message Date
github-actions[bot]
1d2161f805 chore(master): release 1.5.0 2026-03-19 00:11:40 +02:00
3f82e194bb feat: initial_window option 2026-03-19 00:05:09 +02:00
github-actions[bot]
41b7caa50f chore(master): release 1.4.1 2026-02-19 21:19:58 +02:00
1b803786b8 fix: pgup/pgdown scroll 2026-02-09 23:03:06 +02:00
8 changed files with 109 additions and 22 deletions

View File

@@ -1,5 +1,19 @@
# Changelog
## [1.5.0](https://github.com/chenasraf/tx/compare/v1.4.1...v1.5.0) (2026-03-18)
### Features
* initial_window option ([3f82e19](https://github.com/chenasraf/tx/commit/3f82e194bb3352d7a8b889c2d190a118a0d0dd60))
## [1.4.1](https://github.com/chenasraf/tx/compare/v1.4.0...v1.4.1) (2026-02-09)
### Bug Fixes
* pgup/pgdown scroll ([1b80378](https://github.com/chenasraf/tx/commit/1b803786b82ffecf8cd0691ea4605dac8246ed68))
## [1.4.0](https://github.com/chenasraf/tx/compare/v1.3.0...v1.4.0) (2026-02-09)

View File

@@ -152,6 +152,14 @@ webapp:
cwd: .
cmd: npm run watch
# Session with initial window override
webapp:
root: ~/Dev/webapp
initial_window: 0 # open on the "general" window instead of the first configured one
windows:
- ./src
- ./lib
# Session with complex layout
fullstack:
root: ~/Dev/fullstack
@@ -250,12 +258,13 @@ myproject:
#### Available Settings
| Setting | Description |
| ---------------- | ------------------------------------------------- |
| `shell` | Shell to use for command execution |
| `projects_path` | Directory for `tx prj` command (required for prj) |
| `default_layout` | Default pane layout for new windows (see below) |
| `named_layouts` | Reusable named layouts (see below) |
| Setting | Description |
| ---------------- | -------------------------------------------------------------------- |
| `shell` | Shell to use for command execution |
| `projects_path` | Directory for `tx prj` command (required for prj) |
| `default_layout` | Default pane layout for new windows (see below) |
| `named_layouts` | Reusable named layouts (see below) |
| `initial_window` | Window index to select on session creation (default: `1`, see below) |
#### Default Layout
@@ -319,10 +328,30 @@ myproject:
windows:
- name: main
cwd: .
layout: dev # references the "dev" named layout
layout: dev # references the "dev" named layout
- name: logs
cwd: ./logs
layout: simple # references the "simple" named layout
layout: simple # references the "simple" named layout
```
#### Initial Window
The `initial_window` setting controls which window is selected when a new session is created. Window
`0` is the "general" window (created automatically with the session), and configured windows start
at index `1`. The default is `1` (the first configured window).
This can be set globally under `.config` and overridden per session:
```yaml
.config:
initial_window: 1 # global default
myproject:
root: ~/Dev/myproject
initial_window: 0 # override: start on the "general" window
windows:
- ./src
- ./lib
```
#### Shell Resolution Order

View File

@@ -105,6 +105,10 @@ func initConfig(cmd *cobra.Command, args []string) error {
if globalConfig.NamedLayouts != nil {
config.ConfiguredNamedLayouts = globalConfig.NamedLayouts
}
// Apply initial window from config
if globalConfig.InitialWindow != nil {
config.ConfiguredInitialWindow = globalConfig.InitialWindow
}
}
return nil
}

View File

@@ -66,10 +66,20 @@ func ParseConfig(key string, item TmuxConfigItemInput) ParsedTmuxConfigItem {
parsedWindows = append(parsedWindows, parseWindow(w, root))
}
// Resolve initial window: per-session > global > default (1)
initialWindow := 1
if ConfiguredInitialWindow != nil {
initialWindow = *ConfiguredInitialWindow
}
if item.InitialWindow != nil {
initialWindow = *item.InitialWindow
}
return ParsedTmuxConfigItem{
Name: name,
Root: root,
Windows: parsedWindows,
Name: name,
Root: root,
InitialWindow: initialWindow,
Windows: parsedWindows,
}
}

View File

@@ -12,6 +12,7 @@ type GlobalConfig struct {
ProjectsPath string `yaml:"projects_path,omitempty"`
DefaultLayout *TmuxPaneLayout `yaml:"default_layout,omitempty"`
NamedLayouts map[string]*TmuxPaneLayout `yaml:"named_layouts,omitempty"`
InitialWindow *int `yaml:"initial_window,omitempty"`
}
// ConfigFile represents the top-level config file: map of session name -> config
@@ -46,11 +47,12 @@ func (c ConfigFile) Get(key string) (TmuxConfigItemInput, string, bool) {
// TmuxConfigItemInput represents a single tmux session configuration
type TmuxConfigItemInput struct {
Root string `yaml:"root"`
Name string `yaml:"name,omitempty"`
Aliases []string `yaml:"aliases,omitempty"`
BlankWindow bool `yaml:"blank_window,omitempty"`
Windows []TmuxWindowInput `yaml:"windows,omitempty"`
Root string `yaml:"root"`
Name string `yaml:"name,omitempty"`
Aliases []string `yaml:"aliases,omitempty"`
BlankWindow bool `yaml:"blank_window,omitempty"`
InitialWindow *int `yaml:"initial_window,omitempty"`
Windows []TmuxWindowInput `yaml:"windows,omitempty"`
}
// TmuxWindowInput can be either a string (directory path) or a TmuxWindow struct
@@ -144,9 +146,10 @@ type TmuxSplitLayout struct {
// ParsedTmuxConfigItem is the resolved/parsed version of TmuxConfigItemInput
type ParsedTmuxConfigItem struct {
Name string
Root string
Windows []ParsedTmuxWindow
Name string
Root string
InitialWindow int
Windows []ParsedTmuxWindow
}
// ParsedTmuxWindow is the resolved/parsed version of a window
@@ -168,6 +171,9 @@ var ConfiguredDefaultLayout *TmuxPaneLayout
// ConfiguredNamedLayouts holds user-configured named layouts (set from .config)
var ConfiguredNamedLayouts map[string]*TmuxPaneLayout
// ConfiguredInitialWindow holds the user-configured default initial window (set from .config)
var ConfiguredInitialWindow *int
// GetDefaultLayout returns the configured default layout or the hardcoded default
func GetDefaultLayout() *TmuxPaneLayout {
if ConfiguredDefaultLayout != nil {

View File

@@ -111,6 +111,30 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, nil
case tea.KeyPgUp:
half := (m.height - 1) / 2
if half < 1 {
half = 1
}
m.cursor += half
if m.cursor >= len(m.filtered) {
m.cursor = len(m.filtered) - 1
}
m.clampScroll()
return m, nil
case tea.KeyPgDown:
half := (m.height - 1) / 2
if half < 1 {
half = 1
}
m.cursor -= half
if m.cursor < 0 {
m.cursor = 0
}
m.clampScroll()
return m, nil
case tea.KeyRunes:
m.query += string(msg.Runes)
m.refilter()

View File

@@ -63,8 +63,8 @@ func CreateFromConfig(opts exec.Opts, tmuxConfig config.ParsedTmuxConfigItem) er
commands = append(commands, fmt.Sprintf("tmux select-pane -t %s:%s.0", sessionName, windowName))
}
// Select first window
commands = append(commands, fmt.Sprintf("tmux select-window -t %s:1", sessionName))
// Select initial window
commands = append(commands, fmt.Sprintf("tmux select-window -t %s:%d", sessionName, tmuxConfig.InitialWindow))
// Execute all commands
for _, command := range commands {

View File

@@ -1 +1 @@
1.4.0
1.5.0