package config import ( "fmt" "sort" "strings" ) // MultiConfig controls netssh multi. type MultiConfig struct { // Multiplexer is auto, tmux, or zellij; empty means auto. Multiplexer string `mapstructure:"multiplexer"` // PanesPerWindow splits larger host lists into more windows or tabs; 0 = 9. PanesPerWindow int `mapstructure:"panes_per_window"` } // DefaultPanesPerWindow keeps panes readable on a normal screen (3×3). const DefaultPanesPerWindow = 9 // ValidateMulti checks groups and the multi settings. func (c *Config) ValidateMulti() error { switch c.Multi.Multiplexer { case "", "auto", "tmux", "zellij": default: return fmt.Errorf("multi.multiplexer must be auto, tmux, or zellij") } if c.Multi.PanesPerWindow < 0 || c.Multi.PanesPerWindow > 64 { return fmt.Errorf("multi.panes_per_window must be between 1 and 64") } names := make([]string, 0, len(c.Groups)) for name := range c.Groups { names = append(names, name) } sort.Strings(names) for _, name := range names { if !instanceName.MatchString(name) { return fmt.Errorf("groups: name %q must contain only letters, digits, underscores, or hyphens", name) } if len(c.Groups[name]) == 0 { return fmt.Errorf("groups.%s: needs at least one host or selector", name) } for _, selector := range c.Groups[name] { if strings.TrimSpace(selector) == "" || strings.ContainsAny(selector, " \t\n") || strings.HasPrefix(selector, "-") { return fmt.Errorf("groups.%s: invalid entry %q", name, selector) } } } return nil } // PanesPerWindowOrDefault returns the configured value or the default. func (m MultiConfig) PanesPerWindowOrDefault() int { if m.PanesPerWindow > 0 { return m.PanesPerWindow } return DefaultPanesPerWindow }