Skip to content

Commit

Permalink
Support for tmux >= 2.9, with window-size
Browse files Browse the repository at this point in the history
  • Loading branch information
Philipp Heckel committed Oct 3, 2021
1 parent 73111d7 commit 7499e46
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 44 deletions.
62 changes: 18 additions & 44 deletions util/tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,17 @@ import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"text/template"
)

const (
requiredVersion = 2.6 // see issue #
)

var (
tmuxVersionRegex = regexp.MustCompile(`tmux (\d+\.\d+)`)

//go:embed tmux.sh.gotmpl
scriptSource string
scriptTemplate = template.Must(template.New("tmux_script").Parse(scriptSource))
)

// CheckTmuxVersion checks the version of tmux and returns an error if it's not supported
func CheckTmuxVersion() error {
cmd := exec.Command("tmux", "-V")
output, err := cmd.CombinedOutput()
if err != nil {
return err
}
matches := tmuxVersionRegex.FindStringSubmatch(string(output))
if len(matches) <= 1 {
return errors.New("unexpected tmux version output")
}
version, err := strconv.ParseFloat(matches[1], 32)
if err != nil {
return err
}
if version < requiredVersion-0.01 { // floats are fun
return fmt.Errorf("tmux version too low: tmux %.1f required, but found tmux %.1f", requiredVersion, version)
}
return nil
}

// Tmux represents a very special tmux(1) setup, specifially used for REPLbot. It consists of
// two tmux sessions:
// - session "replbot_$id_frame": session with one window and three panes to allow us to resize the terminal of the
Expand All @@ -58,13 +30,14 @@ type Tmux struct {
}

type tmuxScriptParams struct {
MainID, FrameID string
Width, Height int
Env map[string]string
Command string
ConfigFile string
CaptureFile string
LaunchScriptFile string
MainID, FrameID string
Width, Height int
Env map[string]string
Command string
ConfigFile string
CaptureFile string
LaunchScriptFile string
SupportsWindowSize bool
}

// NewTmux creates a new Tmux instance, but does not start the tmux
Expand All @@ -86,15 +59,16 @@ func (s *Tmux) Start(env map[string]string, command ...string) error {
}
defer script.Close()
params := &tmuxScriptParams{
MainID: s.mainID(),
FrameID: s.frameID(),
Width: s.width,
Height: s.height,
Env: env,
Command: QuoteCommand(command),
ConfigFile: s.configFile(),
CaptureFile: s.captureFile(),
LaunchScriptFile: s.launchScriptFile(),
MainID: s.mainID(),
FrameID: s.frameID(),
Width: s.width,
Height: s.height,
Env: env,
Command: QuoteCommand(command),
ConfigFile: s.configFile(),
CaptureFile: s.captureFile(),
LaunchScriptFile: s.launchScriptFile(),
SupportsWindowSize: supportsTmuxWindowSize(),
}
if err := scriptTemplate.Execute(script, params); err != nil {
return err
Expand Down
7 changes: 7 additions & 0 deletions util/tmux.sh.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ command="{{.Command}}"
config_file="{{.ConfigFile}}"
capture_file="{{.CaptureFile}}"
launch_script_file="{{.LaunchScriptFile}}"
supports_window_size="{{if .SupportsWindowSize}}true{{end}}"

# Set up cleanup hooks
cleanup_on_failure() {
Expand Down Expand Up @@ -43,6 +44,9 @@ tmux set-option -t "${main_id}" status off
tmux set-option -t "${main_id}" prefix none
tmux set-option -t "${main_id}" remain-on-exit
tmux set-hook -t "${main_id}" pane-died "capture-pane -S- -E-; save-buffer '${capture_file}'; kill-pane"
if [ -n "${supports_window_size}" ]; then
tmux set-option -t "${main_id}" window-size smallest # default is 'latest' as of tmux >= 2.9
fi

# Start frame tmux session attaches to main session, allows resizing window
tmux -f "${config_file}" new-session -s "${frame_id}" -d -x 200 -y 80 sh -c "while true; do sleep 10; if ! tmux has-session -t '${main_id}'; then exit; fi; done"
Expand All @@ -51,6 +55,9 @@ tmux split-window -v -t "${frame_id}.0" sh -c "while true; do sleep 10; if ! tmu
tmux split-window -h -t "${frame_id}.1" sh -c "unset TMUX; tmux attach -t '${main_id}'"
tmux resize-pane -t "${frame_id}.2" -x "${window_width}" -y "${window_height}"
tmux select-pane -t "${frame_id}.2"
if [ -n "${supports_window_size}" ]; then
tmux set-option -t "${frame_id}" window-size smallest # default is 'latest' as of tmux >= 2.9
fi

# Clean exit
rm -f "${config_file}" "${launch_script_file}"
Expand Down
49 changes: 49 additions & 0 deletions util/tmux_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package util

import (
_ "embed" // required by go:embed
"errors"
"fmt"
"os/exec"
"regexp"
"strconv"
)

const (
minimumTmuxVersion = 2.6 // see issue #39
windowSizeTmuxVersion = 2.9 // see issue #44
)

var (
tmuxVersionRegex = regexp.MustCompile(`tmux (\d+\.\d+)`)
)

// CheckTmuxVersion checks the version of tmux and returns an error if it's not supported
func CheckTmuxVersion() error {
return checkTmuxVersion(minimumTmuxVersion)
}

// supportsTmuxWindowSize checks if the "window-size" option is supported (tmux >= 2.9)
func supportsTmuxWindowSize() bool {
return checkTmuxVersion(windowSizeTmuxVersion) == nil
}

func checkTmuxVersion(compareVersion float64) error {
cmd := exec.Command("tmux", "-V")
output, err := cmd.CombinedOutput()
if err != nil {
return err
}
matches := tmuxVersionRegex.FindStringSubmatch(string(output))
if len(matches) <= 1 {
return errors.New("unexpected tmux version output")
}
version, err := strconv.ParseFloat(matches[1], 32)
if err != nil {
return err
}
if version < compareVersion-0.01 { // floats are fun
return fmt.Errorf("tmux version too low: tmux %.1f required, but found tmux %.1f", compareVersion, version)
}
return nil
}

0 comments on commit 7499e46

Please sign in to comment.