Skip to content

Commit

Permalink
fix multi-select with keywords #73
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnywong committed Jan 13, 2024
1 parent 38dd5a1 commit d43118a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 31 deletions.
2 changes: 1 addition & 1 deletion tssh/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ func chooseAlias(keywords string) (string, bool, error) {
fmt.Fprintf(os.Stderr, "\033[0;32m%s %s\033[0m\r\n", promptSelectedIcon, h.Alias)
}
if len(selectedHosts) > 1 && termMgr != nil {
termMgr.openTerminals(prompt.openType, selectedHosts)
termMgr.openTerminals(keywords, prompt.openType, selectedHosts)
}
return selectedHosts[0].Alias, false, nil
}
Expand Down
8 changes: 1 addition & 7 deletions tssh/tmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const (
)

type terminalManager interface {
openTerminals(openType int, hosts []*sshHost)
openTerminals(keywords string, openType int, hosts []*sshHost)
}

func getTerminalManager() terminalManager {
Expand Down Expand Up @@ -79,12 +79,6 @@ func getPanesMatrix(hosts []*sshHost) [][]*paneHost {
return matrix
}

func appendArgs(alias string, args ...string) []string {
args = append(args, os.Args...)
args = append(args, alias)
return args
}

func setTerminalTitle(title string) {
fmt.Fprintf(os.Stderr, "\033]0;%s\007", title)
}
67 changes: 50 additions & 17 deletions tssh/tmgr_iterm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ import (
)

type iterm2Mgr struct {
app iterm2.App
app iterm2.App
keywords string
}

func (m *iterm2Mgr) openTerminals(openType int, hosts []*sshHost) {
func (m *iterm2Mgr) openTerminals(keywords string, openType int, hosts []*sshHost) {
if len(hosts) < 2 {
return
}
m.keywords = keywords
switch openType {
case openTermDefault:
if len(hosts) > 36 {
Expand All @@ -64,11 +66,30 @@ 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))
func (m *iterm2Mgr) execCmd(session iterm2.Session, alias string) error {
var cmdArgs []string
keywordsMatched := false
for _, arg := range os.Args {
if m.keywords != "" && arg == m.keywords {
if keywordsMatched {
return fmt.Errorf("unable to handle duplicate keywords '%s'", m.keywords)
}
keywordsMatched = true
cmdArgs = append(cmdArgs, alias)
continue
}
cmdArgs = append(cmdArgs, arg)
}
if m.keywords == "" {
cmdArgs = append(cmdArgs, alias)
} else if !keywordsMatched {
return fmt.Errorf("unable to handle replace keywords '%s'", m.keywords)
}
cmd := shellescape.QuoteCommand(cmdArgs)
if err := session.SendText(fmt.Sprintf("%s\n", cmd)); err != nil {
warning("Failed to send text: %v", err)
return fmt.Errorf("failed to send text: %v", err)
}
return nil
}

func (m *iterm2Mgr) getCurrentWindowSession() (iterm2.Window, iterm2.Session) {
Expand Down Expand Up @@ -109,20 +130,23 @@ func (m *iterm2Mgr) openWindows(hosts []*sshHost) {
window, err := m.app.CreateWindow()
if err != nil {
warning("Failed to create window: %v", err)
continue
return
}
tabs, err := window.ListTabs()
if err != nil || len(tabs) == 0 {
warning("Failed to list tabs: %v", err)
continue
return
}
sessions, err := tabs[0].ListSessions()
if err != nil || len(sessions) == 0 {
warning("Failed to list sessions: %v", err)
continue
return
}
m.setTitle(sessions[0], host.Alias)
m.execCmd(sessions[0], host.Alias)
if err := m.execCmd(sessions[0], host.Alias); err != nil {
warning("Failed to execute command: %v", err)
return
}
}
}

Expand All @@ -138,15 +162,18 @@ func (m *iterm2Mgr) openTabs(hosts []*sshHost) {
tab, err := window.CreateTab()
if err != nil {
warning("Failed to create tab: %v", err)
continue
return
}
sessions, err := tab.ListSessions()
if err != nil || len(sessions) == 0 {
warning("Failed to list sessions: %v", err)
continue
return
}
m.setTitle(sessions[0], host.Alias)
m.execCmd(sessions[0], host.Alias)
if err := m.execCmd(sessions[0], host.Alias); err != nil {
warning("Failed to execute command: %v", err)
return
}
}
}

Expand All @@ -163,11 +190,14 @@ func (m *iterm2Mgr) openPanes(hosts []*sshHost) {
pane, err := session.SplitPane(iterm2.SplitPaneOptions{Vertical: false})
if err != nil {
warning("Failed to split pane: %v", err)
continue
return
}
sessions[i] = pane
m.setTitle(pane, matrix[i][0].alias)
m.execCmd(pane, matrix[i][0].alias)
if err := m.execCmd(pane, matrix[i][0].alias); err != nil {
warning("Failed to execute command: %v", err)
return
}
}
for i := 0; i < len(matrix); i++ {
session := sessions[i]
Expand All @@ -178,10 +208,13 @@ func (m *iterm2Mgr) openPanes(hosts []*sshHost) {
pane, err := session.SplitPane(iterm2.SplitPaneOptions{Vertical: true})
if err != nil {
warning("Failed to split pane: %v", err)
continue
return
}
m.setTitle(pane, matrix[i][j].alias)
m.execCmd(pane, matrix[i][j].alias)
if err := m.execCmd(pane, matrix[i][j].alias); err != nil {
warning("Failed to execute command: %v", err)
return
}
}
}
}
Expand All @@ -200,5 +233,5 @@ func getIterm2Manager() terminalManager {
app.Close()
})
debug("running in iTerm2")
return &iterm2Mgr{app}
return &iterm2Mgr{app: app}
}
43 changes: 39 additions & 4 deletions tssh/tmgr_tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,22 @@ SOFTWARE.
package tssh

import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
)

type tmuxMgr struct {
keywords string
}

func (m *tmuxMgr) openTerminals(openType int, hosts []*sshHost) {
func (m *tmuxMgr) openTerminals(keywords string, openType int, hosts []*sshHost) {
if len(hosts) < 2 {
return
}
m.keywords = keywords
switch openType {
case openTermDefault:
if len(hosts) > 36 {
Expand All @@ -55,6 +58,28 @@ func (m *tmuxMgr) openTerminals(openType int, hosts []*sshHost) {
}
}

func (m *tmuxMgr) appendArgs(alias string, args ...string) ([]string, error) {
cmdArgs := args
keywordsMatched := false
for _, arg := range os.Args {
if m.keywords != "" && arg == m.keywords {
if keywordsMatched {
return nil, fmt.Errorf("unable to handle duplicate keywords '%s'", m.keywords)
}
keywordsMatched = true
cmdArgs = append(cmdArgs, alias)
continue
}
cmdArgs = append(cmdArgs, arg)
}
if m.keywords == "" {
cmdArgs = append(cmdArgs, alias)
} else if !keywordsMatched {
return nil, fmt.Errorf("unable to handle replace keywords '%s'", m.keywords)
}
return cmdArgs, nil
}

func (m *tmuxMgr) openWindows(hosts []*sshHost) {
if err := exec.Command("tmux", "renamew", hosts[0].Alias).Run(); err != nil {
warning("Failed to rename tmux window: %v", err)
Expand All @@ -64,8 +89,14 @@ func (m *tmuxMgr) openWindows(hosts []*sshHost) {
})
}
for _, host := range hosts[1:] {
if err := exec.Command("tmux", appendArgs(host.Alias, "neww", "-n", host.Alias)...).Run(); err != nil {
args, err := m.appendArgs(host.Alias, "neww", "-n", host.Alias)
if err != nil {
warning("Failed to open tmux window: %v", err)
return
}
if err := exec.Command("tmux", args...).Run(); err != nil {
warning("Failed to open tmux window: %v", err)
return
}
}
}
Expand Down Expand Up @@ -116,8 +147,12 @@ func (m *tmuxMgr) splitWindow(alias, axes, target, percentage string) string {
if target == "" {
return ""
}
out, err := exec.Command("tmux",
appendArgs(alias, "splitw", axes, "-t", target, "-p", percentage, "-P", "-F", "#{pane_id}")...).Output()
args, err := m.appendArgs(alias, "splitw", axes, "-t", target, "-p", percentage, "-P", "-F", "#{pane_id}")
if err != nil {
warning("Failed to split tmux window: %v", err)
return ""
}
out, err := exec.Command("tmux", args...).Output()
if err != nil {
warning("Failed to split tmux window: %v", err)
return ""
Expand Down
25 changes: 23 additions & 2 deletions tssh/tmgr_wt.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ import (
)

type wtMgr struct {
keywords string
}

func (m *wtMgr) openTerminals(openType int, hosts []*sshHost) {
func (m *wtMgr) openTerminals(keywords string, openType int, hosts []*sshHost) {
if len(hosts) < 2 {
return
}
m.keywords = keywords
switch openType {
case openTermDefault:
if len(hosts) > 36 {
Expand All @@ -64,13 +66,26 @@ func (m *wtMgr) execWt(alias string, args ...string) error {
cmdArgs := []string{"/c", "wt"}
cmdArgs = append(cmdArgs, args...)
cmdArgs = append(cmdArgs, "--title", alias)
keywordsMatched := false
for _, arg := range os.Args {
if strings.Contains(arg, ";") {
return fmt.Errorf("Windows Terminal does not support ';', use '|cat&&' instead.")
}
if m.keywords != "" && arg == m.keywords {
if keywordsMatched {
return fmt.Errorf("unable to handle duplicate keywords '%s'", m.keywords)
}
keywordsMatched = true
cmdArgs = append(cmdArgs, alias)
continue
}
cmdArgs = append(cmdArgs, arg)
}
cmdArgs = append(cmdArgs, alias)
if m.keywords == "" {
cmdArgs = append(cmdArgs, alias)
} else if !keywordsMatched {
return fmt.Errorf("unable to handle replace keywords '%s'", m.keywords)
}
return exec.Command("cmd", cmdArgs...).Run()
}

Expand All @@ -79,6 +94,7 @@ func (m *wtMgr) openWindows(hosts []*sshHost) {
for _, host := range hosts[1:] {
if err := m.execWt(host.Alias, "-w", "-1"); err != nil {
warning("Failed to open wt window: %v", err)
return
}
}
}
Expand All @@ -88,6 +104,7 @@ func (m *wtMgr) openTabs(hosts []*sshHost) {
for _, host := range hosts[1:] {
if err := m.execWt(host.Alias, "-w", "0", "nt"); err != nil {
warning("Failed to open wt tab: %v", err)
return
}
}
}
Expand All @@ -99,24 +116,28 @@ func (m *wtMgr) openPanes(hosts []*sshHost) {
percentage := "." + strconv.Itoa(100/(i+1))
if err := m.execWt(matrix[i][0].alias, "-w", "0", "sp", "-H", "-s", percentage); err != nil {
warning("Failed to split wt pane: %v", err)
return
}
time.Sleep(100 * time.Millisecond) // wait for new pane focus
if err := exec.Command("cmd", "/c", "wt", "-w", "0", "mf", "up").Run(); err != nil {
warning("Failed to move wt focus: %v", err)
return
}
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)
return
}
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))
if err := m.execWt(matrix[i][j].alias, "-w", "0", "sp", "-V", "-s", percentage); err != nil {
warning("Failed to split wt pane: %v", err)
return
}
time.Sleep(100 * time.Millisecond) // wait for new pane focus
}
Expand Down

0 comments on commit d43118a

Please sign in to comment.