diff --git a/README.md b/README.md index 68668e9..70b9c43 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,9 @@ _`~/` 代表 HOME 目录。在 Windows 中,请将下文的 `~/` 替换成 `C:\ # tssh 搜索和选择服务器时,详情中显示的配置列表,默认如下: PromptDetailItems = Alias Host Port User GroupLabels IdentityFile ProxyCommand ProxyJump RemoteCommand + + # 登录后自动设置终端标题,退出后不会重置,你需要参考下文在本地 shell 中设置 PROMPT_COMMAND + SetTerminalTitle = Yes ``` ## 其他功能 @@ -412,7 +415,17 @@ _`~/` 代表 HOME 目录。在 Windows 中,请将下文的 `~/` 替换成 `C:\ - 运行 `tssh --new-host` 可以在 TUI 界面轻松添加 SSH 配置,并且完成后可以立即登录。 -- 运行 `tssh --install-trzsz` 可以自动安装 [trzsz](https://github.com/trzsz/trzsz-go) 到服务器上。默认安装到 `~/.local/bin/` 目录,可以通过 `--install-path /path/to/install` 指定安装目录。若安装目录含有 `~/`,则必须加上单引号,如`--install-path '~/path'`。若获取 `trzsz` 的最新版本号失败,可以通过 `--trzsz-version x.x.x` 参数自行指定。若下载 `trzsz` 的安装包失败,可以自行下载并通过 `--trzsz-bin-path /path/to/trzsz.tar.gz` 参数指定。注意:`--install-trzsz` 不支持跳板机,除非以 `ProxyJump` 的方式绕过跳板机;支持本地是 Windows ,但不支持服务器是 Windows 。 +- 运行 `tssh --install-trzsz` 可以将 [trzsz](https://github.com/trzsz/trzsz-go) ( `trz` / `tsz` ) 安装到服务器上。 + + 默认安装到 `~/.local/bin/` 目录,可以通过 `--install-path /path/to/install` 指定安装目录。 + + 若 `--install-path` 安装目录含有 `~/`,则必须加上单引号,如`--install-path '~/path'`。 + + 若获取 `trzsz` 的最新版本号失败,可以通过 `--trzsz-version x.x.x` 参数自行指定。 + + 若下载 `trzsz` 的安装包失败,可以自行下载并通过 `--trzsz-bin-path /path/to/trzsz.tar.gz` 参数指定。 + + 注意:`--install-trzsz` 不支持 Windows 服务器,不支持跳板机( 除非以 `ProxyJump` 跳过 )。 - 关于修改终端标题,其实无需 `tssh` 就能实现,只要在服务器的 shell 配置文件中(如`~/.bashrc`)配置: @@ -424,6 +437,8 @@ _`~/` 代表 HOME 目录。在 Windows 中,请将下文的 `~/` 替换成 `C:\ PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"' ``` + - 如果在 `~/.tssh.conf` 中设置了 `SetTerminalTitle = Yes`,则会在登录后自动设置终端标题,但是服务器上的 `PROMPT_COMMAND` 会覆盖 `tssh` 设置的标题。在 `tssh` 退出后不会重置为原来的标题,你需要在本地 shell 中设置 `PROMPT_COMMAND`,让它覆盖 `tssh` 设置的标题。 + ## 快捷键 | 操作 | 全局快捷键 | 非搜索快捷键 | 快捷键描述 | diff --git a/go.mod b/go.mod index 3513197..17859f8 100644 --- a/go.mod +++ b/go.mod @@ -6,21 +6,22 @@ require ( github.com/Microsoft/go-winio v0.6.1 github.com/alessio/shellescape v1.4.2 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 - github.com/charmbracelet/bubbles v0.16.1 - github.com/charmbracelet/bubbletea v0.24.2 + github.com/charmbracelet/bubbles v0.17.1 + github.com/charmbracelet/bubbletea v0.25.0 github.com/charmbracelet/lipgloss v0.9.1 github.com/chzyer/readline v1.5.1 + github.com/creack/pty v1.1.21 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/mattn/go-isatty v0.0.20 github.com/mitchellh/go-homedir v1.1.0 github.com/skeema/knownhosts v1.2.1 github.com/stretchr/testify v1.8.4 github.com/trzsz/go-arg v1.5.3 - github.com/trzsz/iterm2 v0.1.1 + github.com/trzsz/iterm2 v0.1.2 github.com/trzsz/promptui v0.10.5 github.com/trzsz/ssh_config v1.3.4 - github.com/trzsz/trzsz-go v1.1.7-0.20231209142115-a64ab46112dc - golang.org/x/crypto v0.16.0 + github.com/trzsz/trzsz-go v1.1.7 + golang.org/x/crypto v0.17.0 golang.org/x/sys v0.15.0 golang.org/x/term v0.15.0 ) @@ -33,7 +34,6 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect - github.com/creack/pty v1.1.21 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f // indirect github.com/gorilla/websocket v1.5.1 // indirect @@ -55,7 +55,7 @@ require ( golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.16.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/tools v0.16.1 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c5b8b81..a6e6185 100644 --- a/go.sum +++ b/go.sum @@ -16,10 +16,10 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY= -github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc= -github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY= -github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg= +github.com/charmbracelet/bubbles v0.17.1 h1:0SIyjOnkrsfDo88YvPgAWvZMwXe26TP6drRvmkjyUu4= +github.com/charmbracelet/bubbles v0.17.1/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o= +github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= +github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -37,9 +37,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f h1:OGqDDftRTwrvUoL6pOG7rYTmWsTCvyEWFsMjg+HcOaA= github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -86,17 +84,17 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/trzsz/go-arg v1.5.3 h1:eIDwDEmvSahtr5HpQOLrSa+YMqWQQ0H20xx60XgXQJw= github.com/trzsz/go-arg v1.5.3/go.mod h1:IC6Z/FiVH7uYvcbp1/gJhDYCFPS/GkL0APYakVvgY4I= -github.com/trzsz/iterm2 v0.1.1 h1:UZ+Su5xOuBNDXpRStfuMCsTWhajNnKEHChJ4tfd62Mc= -github.com/trzsz/iterm2 v0.1.1/go.mod h1:PMI+3JcT7J9D0T6e3mOWv8ICYdrrNZwuge3Tm7zDLws= +github.com/trzsz/iterm2 v0.1.2 h1:VwfLzr2fKeaLf+p4tS0ms+kqdiQQxVLbTJUoyuQXmK8= +github.com/trzsz/iterm2 v0.1.2/go.mod h1:PMI+3JcT7J9D0T6e3mOWv8ICYdrrNZwuge3Tm7zDLws= github.com/trzsz/promptui v0.10.5 h1:tlzJkx+JOeE0sqKWmqgaoToZiYqj5G1Mz+QDV97VFu8= github.com/trzsz/promptui v0.10.5/go.mod h1:GMZtu6ZTzU73CBFkzGtmB4wnTROIAbv4GFA74fV8V8g= github.com/trzsz/ssh_config v1.3.4 h1:7of+6rUmdWdqfgXnH9csgJe1kNkriS9xOiFGx4KCkEw= github.com/trzsz/ssh_config v1.3.4/go.mod h1:Dl1okTjVVfsrtTA8nqkJ1OnjiCrZY6DUEI2DGT2/YoQ= -github.com/trzsz/trzsz-go v1.1.7-0.20231209142115-a64ab46112dc h1:tca7M5OF80E9JPiHtS/j4z7+yAtp56c6ecY8cojg58o= -github.com/trzsz/trzsz-go v1.1.7-0.20231209142115-a64ab46112dc/go.mod h1:3OBY6NJx3Z7A5akhfunPkhh6Qtk9lMwnP/YCwjIu16g= +github.com/trzsz/trzsz-go v1.1.7 h1:sPwLHkQGeXwbFM/GcZ8I5ie+mSS+dZCGAifOWeiIQ6o= +github.com/trzsz/trzsz-go v1.1.7/go.mod h1:3OBY6NJx3Z7A5akhfunPkhh6Qtk9lMwnP/YCwjIu16g= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= @@ -116,13 +114,11 @@ golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tssh/config.go b/tssh/config.go index acb170d..533fd10 100644 --- a/tssh/config.go +++ b/tssh/config.go @@ -75,6 +75,7 @@ type tsshConfig struct { promptPageSize uint8 promptDefaultMode string promptDetailItems string + setTerminalTitle string loadConfig sync.Once loadExConfig sync.Once loadHosts sync.Once @@ -138,9 +139,17 @@ func parseTsshConfig() { userConfig.promptDefaultMode = value case name == "promptdetailitems" && userConfig.promptDetailItems == "": userConfig.promptDetailItems = value + case name == "setterminaltitle" && userConfig.setTerminalTitle == "": + userConfig.setTerminalTitle = value } } + if enableDebugLogging { + showTsshConfig() + } +} + +func showTsshConfig() { if userConfig.configPath != "" { debug("ConfigPath = %s", userConfig.configPath) } @@ -162,6 +171,9 @@ func parseTsshConfig() { if userConfig.promptDetailItems != "" { debug("PromptDetailItems = %s", userConfig.promptDetailItems) } + if userConfig.setTerminalTitle != "" { + debug("SetTerminalTitle = %s", userConfig.setTerminalTitle) + } } func initUserConfig(configFile string) error { diff --git a/tssh/main.go b/tssh/main.go index 1c4a722..94b0dfd 100644 --- a/tssh/main.go +++ b/tssh/main.go @@ -288,6 +288,14 @@ func sshStart(args *sshArgs) error { return nil } + // set terminal title + if userConfig.setTerminalTitle != "" { + switch strings.ToLower(userConfig.setTerminalTitle) { + case "yes", "true": + setTerminalTitle(args.Destination) + } + } + // execute remote tools if necessary execRemoteTools(args, client) diff --git a/tssh/tmgr.go b/tssh/tmgr.go index 5687e9d..44f3659 100644 --- a/tssh/tmgr.go +++ b/tssh/tmgr.go @@ -26,6 +26,7 @@ SOFTWARE. package tssh import ( + "fmt" "math" "os" ) @@ -83,3 +84,7 @@ func appendArgs(alias string, args ...string) []string { args = append(args, alias) return args } + +func setTerminalTitle(title string) { + fmt.Printf("\033]0;%s\007", title) +} diff --git a/tssh/tmgr_iterm2.go b/tssh/tmgr_iterm2.go index 2734c74..cca57d2 100644 --- a/tssh/tmgr_iterm2.go +++ b/tssh/tmgr_iterm2.go @@ -60,6 +60,10 @@ func (m *iterm2Mgr) openTerminals(openType int, hosts []*sshHost) { } } +func (m *iterm2Mgr) setTitle(session iterm2.Session, alias string) { + _ = session.Inject([]byte(fmt.Sprintf("\033]0;%s\007", alias))) +} + func (m *iterm2Mgr) execCmd(session iterm2.Session, alias string) { cmd := shellescape.QuoteCommand(append(os.Args, alias)) if err := session.SendText(fmt.Sprintf("%s\n", cmd)); err != nil { @@ -98,6 +102,9 @@ func (m *iterm2Mgr) getCurrentWindowSession() (iterm2.Window, iterm2.Session) { } func (m *iterm2Mgr) openWindows(hosts []*sshHost) { + if _, session := m.getCurrentWindowSession(); session != nil { + m.setTitle(session, hosts[0].Alias) + } for _, host := range hosts[1:] { window, err := m.app.CreateWindow() if err != nil { @@ -114,16 +121,19 @@ func (m *iterm2Mgr) openWindows(hosts []*sshHost) { warning("Failed to list sessions: %v", err) continue } - _ = window.SetTitle(host.Alias) + m.setTitle(sessions[0], host.Alias) m.execCmd(sessions[0], host.Alias) } } func (m *iterm2Mgr) openTabs(hosts []*sshHost) { - window, _ := m.getCurrentWindowSession() + window, session := m.getCurrentWindowSession() if window == nil { return } + if session != nil { + m.setTitle(session, hosts[0].Alias) + } for _, host := range hosts[1:] { tab, err := window.CreateTab() if err != nil { @@ -135,13 +145,17 @@ func (m *iterm2Mgr) openTabs(hosts []*sshHost) { warning("Failed to list sessions: %v", err) continue } - _ = tab.SetTitle(host.Alias) + m.setTitle(sessions[0], host.Alias) m.execCmd(sessions[0], host.Alias) } } func (m *iterm2Mgr) openPanes(hosts []*sshHost) { _, session := m.getCurrentWindowSession() + if session == nil { + return + } + m.setTitle(session, hosts[0].Alias) matrix := getPanesMatrix(hosts) sessions := make([]iterm2.Session, len(matrix)) sessions[0] = session @@ -152,6 +166,7 @@ func (m *iterm2Mgr) openPanes(hosts []*sshHost) { continue } sessions[i] = pane + m.setTitle(pane, matrix[i][0].alias) m.execCmd(pane, matrix[i][0].alias) } for i := 0; i < len(matrix); i++ { @@ -165,6 +180,7 @@ func (m *iterm2Mgr) openPanes(hosts []*sshHost) { warning("Failed to split pane: %v", err) continue } + m.setTitle(pane, matrix[i][j].alias) m.execCmd(pane, matrix[i][j].alias) } } diff --git a/tssh/tmgr_tmux.go b/tssh/tmgr_tmux.go index 2b2fba8..2a79c83 100644 --- a/tssh/tmgr_tmux.go +++ b/tssh/tmgr_tmux.go @@ -72,12 +72,14 @@ func (m *tmuxMgr) openWindows(hosts []*sshHost) { func (m *tmuxMgr) openPanes(hosts []*sshHost) { matrix := getPanesMatrix(hosts) - out, err := exec.Command("tmux", "display", "-p", "#{pane_id}").Output() + out, err := exec.Command("tmux", "display", "-p", "#{pane_id}|#{pane_title}").Output() if err != nil { - warning("Failed to get tmux pane id: %v", err) + warning("Failed to get tmux pane id and title: %v", err) return } - matrix[0][0].paneId = strings.TrimSpace(string(out)) + output := strings.TrimSpace(string(out)) + tokens := strings.SplitN(output, "|", 2) + matrix[0][0].paneId = tokens[0] for i := len(matrix) - 1; i > 0; i-- { matrix[i][0].paneId = m.splitWindow(matrix[i][0].alias, "-v", matrix[0][0].paneId, strconv.Itoa(100/(i+1))) } @@ -86,6 +88,21 @@ func (m *tmuxMgr) openPanes(hosts []*sshHost) { matrix[i][j].paneId = m.splitWindow(matrix[i][j].alias, "-h", matrix[i][0].paneId, strconv.Itoa(100/(j+1))) } } + // change panes title + for i := 0; i < len(matrix); i++ { + for j := 0; j < len(matrix[i]); j++ { + if matrix[i][j].paneId != "" { + _ = exec.Command("tmux", "selectp", "-t", matrix[i][j].paneId, "-T", matrix[i][j].alias).Run() + } + } + } + if len(tokens) > 1 && tokens[1] != "" { + // reset pane title after exit + onExitFuncs = append(onExitFuncs, func() { + _ = exec.Command("tmux", "selectp", "-t", tokens[0], "-T", tokens[1]).Run() + }) + } + // reset panes order for i := 0; i < len(matrix); i++ { for j := 0; j < len(matrix[i]); j++ { if matrix[i][j].paneId != "" { diff --git a/tssh/tmgr_wt.go b/tssh/tmgr_wt.go index a60ccb6..53ec6b5 100644 --- a/tssh/tmgr_wt.go +++ b/tssh/tmgr_wt.go @@ -75,6 +75,7 @@ func (m *wtMgr) execWt(alias string, args ...string) error { } func (m *wtMgr) openWindows(hosts []*sshHost) { + setTerminalTitle(hosts[0].Alias) for _, host := range hosts[1:] { if err := m.execWt(host.Alias, "-w", "-1"); err != nil { warning("Failed to open wt window: %v", err) @@ -83,6 +84,7 @@ func (m *wtMgr) openWindows(hosts []*sshHost) { } func (m *wtMgr) openTabs(hosts []*sshHost) { + setTerminalTitle(hosts[0].Alias) for _, host := range hosts[1:] { if err := m.execWt(host.Alias, "-w", "0", "nt"); err != nil { warning("Failed to open wt tab: %v", err) @@ -91,6 +93,7 @@ func (m *wtMgr) openTabs(hosts []*sshHost) { } func (m *wtMgr) openPanes(hosts []*sshHost) { + setTerminalTitle(hosts[0].Alias) matrix := getPanesMatrix(hosts) for i := len(matrix) - 1; i > 0; i-- { percentage := "." + strconv.Itoa(100/(i+1)) @@ -101,12 +104,14 @@ func (m *wtMgr) openPanes(hosts []*sshHost) { if err := exec.Command("cmd", "/c", "wt", "-w", "0", "mf", "up").Run(); err != nil { warning("Failed to move wt focus: %v", err) } + time.Sleep(100 * time.Millisecond) // wait for new pane focus } for i := 0; i < len(matrix); i++ { if i > 0 { if err := exec.Command("cmd", "/c", "wt", "-w", "0", "mf", "down").Run(); err != nil { warning("Failed to move wt focus: %v", err) } + time.Sleep(100 * time.Millisecond) // wait for new pane focus } for j := 1; j < len(matrix[i]); j++ { percentage := "." + strconv.Itoa(100-100/(len(matrix[i])-j+1))