github.com/japiotr123/go-tmux@v0.0.0-20231125144807-6c27c6cf74ba/session.go (about)

     1  // The MIT License (MIT)
     2  // Copyright (C) 2019-2023 Georgiy Komarov <jubnzv@gmail.com>
     3  
     4  package tmux
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"regexp"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  // Represents a tmux session:
    15  // https://github.com/tmux/tmux/wiki/Getting-Started#sessions-windows-and-panes
    16  type Session struct {
    17  	Id             int      // Session id
    18  	Name           string   // Session name
    19  	StartDirectory string   // Path to window start directory
    20  	Windows        []Window // List of windows used on session initialization
    21  }
    22  
    23  // Creates a new session object.
    24  func NewSession(id int, name, startDirectory string, windows []Window) *Session {
    25  	return &Session{
    26  		Id:             id,
    27  		Name:           name,
    28  		StartDirectory: startDirectory,
    29  		Windows:        windows,
    30  	}
    31  }
    32  
    33  // Checks tmux rules for sessions naming. Reference:
    34  // https://github.com/tmux/tmux/blob/5489796737108cb9bba01f831421e531a50b946b/session.c#L238
    35  func checkSessionName(name string) bool {
    36  	if len(name) == 0 {
    37  		return false
    38  	}
    39  	if strings.Contains(name, ":") {
    40  		return false
    41  	}
    42  	if strings.Contains(name, ".") {
    43  		return false
    44  	}
    45  	return true
    46  }
    47  
    48  // Adds the window to the session configuration. This will change only
    49  // in-library session representation. Used for initial configuration before
    50  // creating a new session.
    51  func (s *Session) AddWindow(window Window) {
    52  	s.Windows = append(s.Windows, window)
    53  }
    54  
    55  // Lists all windows in the current session.
    56  func (s *Session) ListWindows() ([]Window, error) {
    57  	args := []string{
    58  		"list-windows",
    59  		"-t", s.Name,
    60  		"-F", "#{window_id}:#{window_name}:#{pane_current_path}"}
    61  
    62  	out, _, err := RunCmd(args)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	outLines := strings.Split(out, "\n")
    68  	windows := []Window{}
    69  	re := regexp.MustCompile(`@([0-9]+):(.+):(.+)`)
    70  	for _, line := range outLines {
    71  		result := re.FindStringSubmatch(line)
    72  		if len(result) < 4 {
    73  			continue
    74  		}
    75  		id, err_atoi := strconv.Atoi(result[1])
    76  		if err_atoi != nil {
    77  			return nil, err_atoi
    78  		}
    79  
    80  		windows = append(windows, Window{
    81  			Name:           result[2],
    82  			Id:             id,
    83  			StartDirectory: result[3],
    84  			SessionName:    s.Name,
    85  			SessionId:      s.Id})
    86  	}
    87  
    88  	return windows, nil
    89  }
    90  
    91  // Attach to existing tmux session.
    92  func (s *Session) AttachSession() error {
    93  	args := []string{}
    94  	// If run inside tmux, switch the current session to the new one.
    95  	if !IsInsideTmux() {
    96  		args = append(args, "attach-session", "-t", s.Name)
    97  	} else {
    98  		args = append(args, "switch-client", "-t", s.Name)
    99  	}
   100  
   101  	if err := ExecCmd(args); err != nil {
   102  		return err
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // Detaches from the current session.
   109  // Detaching from the tmux session means that the client exits and detaches
   110  // from the outside terminal.
   111  // See: https://github.com/tmux/tmux/wiki/Getting-Started#attaching-and-detaching
   112  func (s *Session) DettachSession() error {
   113  	args := []string{
   114  		"detach-client",
   115  		"-s", s.Name}
   116  	if err := ExecCmd(args); err != nil {
   117  		return err
   118  	}
   119  	return nil
   120  }
   121  
   122  // Creates a new window inside this session.
   123  func (s *Session) NewWindow(name string) (window Window, err error) {
   124  	args := []string{
   125  		"new-window",
   126  		"-d",
   127  		"-t", fmt.Sprintf("%s:", s.Name),
   128  		"-n", name,
   129  		"-F", "#{window_id}:#{window_name}", "-P"}
   130  	out, _, err_exec := RunCmd(args)
   131  	if err_exec != nil {
   132  		return window, err_exec
   133  	}
   134  
   135  	re := regexp.MustCompile(`@([0-9]+):(.+)`)
   136  	result := re.FindStringSubmatch(out)
   137  	if len(result) < 3 {
   138  		return window, errors.New("Error creating new window")
   139  	}
   140  	id, err_atoi := strconv.Atoi(result[1])
   141  	if err_atoi != nil {
   142  		return window, err_atoi
   143  	}
   144  
   145  	pane := Pane{
   146  		SessionId:   s.Id,
   147  		SessionName: s.Name,
   148  		WindowId:    id,
   149  		WindowName:  result[2],
   150  		WindowIndex: 0}
   151  	new_window := Window{
   152  		Name:        result[2],
   153  		Id:          id,
   154  		SessionName: s.Name,
   155  		SessionId:   s.Id,
   156  		Panes:       []Pane{pane}}
   157  	return new_window, nil
   158  }
   159  
   160  // Returns list with all panes for this session.
   161  func (s *Session) ListPanes() ([]Pane, error) {
   162  	return ListPanes([]string{"-s", "-t", s.Name})
   163  }
   164  
   165  // Returns a name of the attached tmux session.
   166  func GetAttachedSessionName() (string, error) {
   167  	args := []string{
   168  		"display-message",
   169  		"-p", "#S"}
   170  	out, _, err := RunCmd(args)
   171  	if err != nil {
   172  		return "", err
   173  	}
   174  
   175  	// Remove trailing CR
   176  	out = out[:len(out)-1]
   177  
   178  	return out, nil
   179  }