File: tmux.go

package info (click to toggle)
kitty 0.42.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 28,564 kB
  • sloc: ansic: 82,787; python: 55,191; objc: 5,122; sh: 1,295; xml: 364; makefile: 143; javascript: 78
file content (104 lines) | stat: -rw-r--r-- 2,444 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>

package tui

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/shirou/gopsutil/process"
	"golang.org/x/sys/unix"

	"github.com/kovidgoyal/kitty/tools/utils"
)

var _ = fmt.Print

var TmuxExe = sync.OnceValue(func() string {
	return utils.FindExe("tmux")
})

func tmux_socket_address() (socket string) {
	socket = os.Getenv("TMUX")
	if socket == "" {
		return ""
	}
	addr, pid_str, found := strings.Cut(socket, ",")
	if !found {
		return ""
	}
	if unix.Access(addr, unix.R_OK|unix.W_OK) != nil {
		return ""
	}
	pid_str, _, _ = strings.Cut(pid_str, ",")
	pid, err := strconv.ParseInt(pid_str, 10, 32)
	if err != nil {
		return ""
	}
	p, err := process.NewProcess(int32(pid))
	if err != nil {
		return ""
	}
	cmd, err := p.CmdlineSlice()
	if err != nil {
		return ""
	}
	if len(cmd) > 0 && strings.ToLower(filepath.Base(cmd[0])) != "tmux" {
		return ""
	}
	return socket
}

var TmuxSocketAddress = sync.OnceValue(tmux_socket_address)

func tmux_command(args ...string) (c *exec.Cmd, stderr *strings.Builder) {
	c = exec.Command(TmuxExe(), args...)
	stderr = &strings.Builder{}
	c.Stderr = stderr
	return c, stderr
}

func tmux_allow_passthrough() error {
	c, stderr := tmux_command("show", "-Ap", "allow-passthrough")
	allowed, not_allowed := errors.New("allowed"), errors.New("not allowed")
	get_result := make(chan error)
	go func() {
		output, err := c.Output()
		if err != nil {
			get_result <- fmt.Errorf("Running %#v failed with error: %w. STDERR: %s", c.Args, err, stderr.String())
		} else {
			q := strings.TrimSpace(utils.UnsafeBytesToString(output))
			if strings.HasSuffix(q, " on") || strings.HasSuffix(q, " all") {
				get_result <- allowed
			} else {
				get_result <- not_allowed
			}
		}
	}()
	select {
	case r := <-get_result:
		if r == allowed {
			return nil
		}
		if r != not_allowed {
			return r
		}
		c, stderr = tmux_command("set", "-p", "allow-passthrough", "on")
		err := c.Run()
		if err != nil {
			err = fmt.Errorf("Running %#v failed with error: %w. STDERR: %s", c.Args, err, stderr.String())
		}
		return err
	case <-time.After(2 * time.Second):
		return fmt.Errorf("Tmux command timed out. This often happens when the version of tmux on your PATH is older than the version of the running tmux server")
	}
}

var TmuxAllowPassthrough = sync.OnceValue(tmux_allow_passthrough)