131 lines
3.3 KiB
Go
131 lines
3.3 KiB
Go
package tmux
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// CreateSession creates a new tmux session with the given name and working directory.
|
|
func CreateSession(name, workDir string) error {
|
|
return run("new-session", "-d", "-s", name, "-c", workDir)
|
|
}
|
|
|
|
// SetOption sets a tmux user option on a session.
|
|
func SetOption(session, key, value string) error {
|
|
return run("set-option", "-t", session, key, value)
|
|
}
|
|
|
|
// GetOption reads a tmux user option from a session.
|
|
func GetOption(session, key string) (string, error) {
|
|
out, err := output("show-option", "-t", session, "-v", key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(out), nil
|
|
}
|
|
|
|
// SendKeys sends keystrokes to a tmux session.
|
|
func SendKeys(session, keys string) error {
|
|
return run("send-keys", "-t", session, "-l", keys)
|
|
}
|
|
|
|
// SendEnter sends an Enter keystroke to a tmux session.
|
|
func SendEnter(session string) error {
|
|
return run("send-keys", "-t", session, "Enter")
|
|
}
|
|
|
|
// ListSessions returns all tmux session names.
|
|
func ListSessions() ([]string, error) {
|
|
out, err := output("list-sessions", "-F", "#{session_name}")
|
|
if err != nil {
|
|
// No sessions is not an error
|
|
if strings.Contains(err.Error(), "no server running") ||
|
|
strings.Contains(err.Error(), "no sessions") {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
lines := strings.Split(strings.TrimSpace(out), "\n")
|
|
var sessions []string
|
|
for _, line := range lines {
|
|
line = strings.TrimSpace(line)
|
|
if line != "" {
|
|
sessions = append(sessions, line)
|
|
}
|
|
}
|
|
return sessions, nil
|
|
}
|
|
|
|
// ListSessionsWithPrefix returns tmux sessions matching a prefix.
|
|
func ListSessionsWithPrefix(prefix string) ([]string, error) {
|
|
all, err := ListSessions()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var result []string
|
|
for _, s := range all {
|
|
if strings.HasPrefix(s, prefix) {
|
|
result = append(result, s)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// KillSession kills a tmux session.
|
|
func KillSession(session string) error {
|
|
return run("kill-session", "-t", session)
|
|
}
|
|
|
|
// HasSession checks if a tmux session exists.
|
|
func HasSession(session string) bool {
|
|
err := run("has-session", "-t", session)
|
|
return err == nil
|
|
}
|
|
|
|
// SessionAttachedClients returns the number of clients attached to a session.
|
|
func SessionAttachedClients(session string) (int, error) {
|
|
out, err := output("display-message", "-t", session, "-p", "#{session_attached}")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
val := strings.TrimSpace(out)
|
|
if val == "" {
|
|
return 0, nil
|
|
}
|
|
n := 0
|
|
for _, c := range val {
|
|
if c >= '0' && c <= '9' {
|
|
n = n*10 + int(c-'0')
|
|
}
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
// SendCtrlC sends Ctrl-C to interrupt the current pane command.
|
|
func SendCtrlC(session string) error {
|
|
return run("send-keys", "-t", session, "C-c")
|
|
}
|
|
|
|
// RespawnPane replaces the current pane content with a new command.
|
|
func RespawnPane(session, cmd string) error {
|
|
return run("respawn-pane", "-k", "-t", session, cmd)
|
|
}
|
|
|
|
func run(args ...string) error {
|
|
cmd := exec.Command("tmux", args...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("tmux %s: %w: %s", args[0], err, string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func output(args ...string) (string, error) {
|
|
cmd := exec.Command("tmux", args...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return "", fmt.Errorf("tmux %s: %w: %s", args[0], err, string(out))
|
|
}
|
|
return string(out), nil
|
|
}
|