Files
dotfiles/sesh/main.go
T
2026-01-24 11:46:44 +01:00

155 lines
3.0 KiB
Go

package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"github.com/ktr0731/go-fuzzyfinder"
"gopkg.in/yaml.v3"
)
type Window struct {
Path string `yaml:"path"`
Name string `yaml:"name"`
Program string `yaml:"program"`
}
func (w Window) ExpandedPath() string {
expanded, err := expandTilde(w.Path)
if err != nil {
panic(err)
}
return expanded
}
type Config map[string][]Window
const (
tmux = "tmux"
mkdir = "mkdir"
)
func main() {
_, err := exec.LookPath(tmux)
if err != nil {
panic(err)
}
_, err = exec.LookPath(mkdir)
if err != nil {
panic(err)
}
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
configFilePath := filepath.Join(homeDir, ".sesh.yaml")
f, err := os.Open(configFilePath)
if err != nil {
panic(err)
}
var config Config
err = yaml.NewDecoder(f).Decode(&config)
if err != nil {
panic(err)
}
seshNames := make([]string, 0, len(config))
for seshName := range config {
seshNames = append(seshNames, seshName)
}
i, err := fuzzyfinder.Find(seshNames, func(i int) string {
return seshNames[i]
})
if err != nil {
return
}
seshName := seshNames[i]
if HasSession(seshName) {
TurnIntoTmux(seshName)
} else {
sesh := config[seshName]
if len(sesh) == 0 {
fmt.Println("no windows in session")
return
}
for _, window := range sesh {
// TODO: use go stdandard library instead
exec.Command(mkdir, "-p", window.ExpandedPath()).Run()
}
for _, window := range sesh {
NewWindowInSession(seshName, window)
}
exec.Command(tmux, "select-window", "-t", fmt.Sprintf("%s:^", seshName)).Run()
TurnIntoTmux(seshName)
}
}
var sessionCache = make(map[string]bool)
func HasSession(seshName string) bool {
has, ok := sessionCache[seshName]
if ok {
return has
}
res := exec.Command(tmux, "has-session", "-t", seshName).Run()
has = res == nil
sessionCache[seshName] = has
return has
}
func expandTilde(path string) (string, error) {
if !strings.HasPrefix(path, "~") {
return path, nil
}
userHomeDir, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(userHomeDir, path[1:]), nil
}
func NewWindowInSession(seshName string, window Window) {
if seshName == "" {
panic("missing seshName")
}
var args = []string{}
if HasSession(seshName) {
args = append(args, "new-window", "-t", seshName)
} else {
args = append(args, "new-session", "-d", "-s", seshName)
}
if window.ExpandedPath() != "" {
args = append(args, "-c", window.ExpandedPath())
}
if window.Name != "" {
args = append(args, "-n", window.Name)
}
if window.Program != "" {
args = append(args, window.Program)
}
exec.Command(tmux, args...).Run()
}
func TurnIntoTmux(sessionName string) {
_, isInTmux := os.LookupEnv("TMUX")
tmuxPath, err := exec.LookPath(tmux)
if err != nil {
panic(err)
}
if isInTmux {
err = syscall.Exec(tmuxPath, []string{tmuxPath, "switch-client", "-t", sessionName}, os.Environ())
} else {
err = syscall.Exec(tmuxPath, []string{tmuxPath, "attach", "-t", sessionName}, os.Environ())
}
if err != nil {
panic(err)
}
}