Skip to content

Commit b6f0de4

Browse files
authored
feat: implement config and startup scripts (#22)
Implements parsing of a sesh/sesh.toml config file and creates a pattern for future use. Add the ability to configure a startup script for a project
1 parent db29565 commit b6f0de4

File tree

11 files changed

+160
-30
lines changed

11 files changed

+160
-30
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ You can customize this however you want, see `man fzf` for more info on the diff
7777
sesh connect (sesh list | zf --height 24)
7878
```
7979

80+
## Configuration
81+
82+
To configure `sesh`, you will need to create `sesh/sesh.toml` with `$XDG_CONFIG_HOME` or `$HOME/.config` as the root directory, depending on whether the former has been set. On MacOS, this will likely be `~/.config/` by default and therefore the configuration filepath would be `~/.config/sesh/sesh.toml`. See the [Go docs](https://cs.opensource.google/go/go/+/go1.21.6:src/os/file.go;l=460) for more information.
83+
84+
An example of the `sesh.toml` file is shown below with all configurable options and their default values:
85+
86+
```toml
87+
default_startup_script = "~/git_repos/dotfiles/bin/sesh/default.sh"
88+
89+
[[startup_scripts]]
90+
session_path = "~/git_repos/sesh"
91+
script_path = "~/git_repos/dotfiles/bin/sesh/sesh.sh"
92+
```
93+
94+
### Startup Scripts
95+
96+
Startup scripts will be ignored if the `--command/-c` flag is passed! Startup scripts will only be run upon session creation!
97+
98+
If a `[[startup_scripts]]` entry is present for a given session path, then the startup script path specified by `script_path` will be run when the session is created. Otherwise, if `default_startup_script` is specified, then the script at that path will be executed. Make sure that the scripts specified are executable, e.g. `chmod +x ~/git_repos/dotfiles/bin/sesh/default.sh`.
99+
80100
## Background (the "t" script)
81101

82102
Sesh is the successor to my popular [t-smart-tmux-session-manager](https://github.com/joshmedeski/t-smart-tmux-session-manager) tmux plugin. After a year of development and over 250 stars, it's clear that people enjoy the idea of a smart session manager. However, I've always felt that the tmux plugin was a bit of a hack. It's a bash script that runs in the background and parses the output of tmux commands. It works, but it's not ideal and isn't flexible enough to support other terminal multiplexers.

cmds/choose.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
cli "github.com/urfave/cli/v2"
1111

12+
"github.com/joshmedeski/sesh/config"
1213
"github.com/joshmedeski/sesh/connect"
1314
"github.com/joshmedeski/sesh/session"
1415
)
@@ -65,7 +66,8 @@ func Choose() *cli.Command {
6566
}
6667
choice := strings.TrimSpace(cmdOutput.String())
6768
// TODO: get choice from Session structs array
68-
return connect.Connect(choice, false, "")
69+
config := config.ParseConfigFile()
70+
return connect.Connect(choice, false, "", &config)
6971
},
7072
}
7173
}

cmds/clone.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmds
33
import (
44
cli "github.com/urfave/cli/v2"
55

6+
"github.com/joshmedeski/sesh/config"
67
"github.com/joshmedeski/sesh/connect"
78
"github.com/joshmedeski/sesh/git"
89
)
@@ -32,8 +33,8 @@ func Clone() *cli.Command {
3233
if err != nil {
3334
return cli.Exit(err, 1)
3435
}
35-
36-
return connect.Connect(c.Path, false, "")
36+
config := config.ParseConfigFile()
37+
return connect.Connect(c.Path, false, "", &config)
3738
},
3839
}
3940
}

cmds/connect.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmds
33
import (
44
cli "github.com/urfave/cli/v2"
55

6+
"github.com/joshmedeski/sesh/config"
67
"github.com/joshmedeski/sesh/connect"
78
)
89

@@ -31,7 +32,8 @@ func Connect() *cli.Command {
3132
if session == "" {
3233
return cli.Exit("No session provided", 0)
3334
}
34-
return connect.Connect(session, alwaysSwitch, command)
35+
config := config.ParseConfigFile()
36+
return connect.Connect(session, alwaysSwitch, command, &config)
3537
},
3638
}
3739
}

config/config.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path"
7+
"path/filepath"
8+
"runtime"
9+
10+
"github.com/pelletier/go-toml/v2"
11+
)
12+
13+
type (
14+
Script struct {
15+
SessionPath string `toml:"session_path"`
16+
ScriptPath string `toml:"script_path"`
17+
}
18+
Config struct {
19+
StartupScripts []Script `toml:"startup_scripts"`
20+
DefaultStartupScript string `toml:"default_startup_script"`
21+
}
22+
)
23+
24+
func getUserConfigDir() (string, error) {
25+
switch runtime.GOOS {
26+
case "darwin":
27+
// typically ~/Library/Application Support, but we want to use ~/.config
28+
homeDir, err := os.UserHomeDir()
29+
if err != nil {
30+
return "", err
31+
}
32+
return path.Join(homeDir, ".config"), nil
33+
default:
34+
return os.UserConfigDir()
35+
}
36+
}
37+
38+
func ParseConfigFile() Config {
39+
config := Config{}
40+
configDir, err := getUserConfigDir()
41+
if err != nil {
42+
fmt.Printf(
43+
"Error determining the user config directory: %s\nUsing default config instead",
44+
err,
45+
)
46+
return config
47+
}
48+
configPath := filepath.Join(configDir, "sesh", "sesh.toml")
49+
data, err := os.ReadFile(configPath)
50+
if err != nil {
51+
return config
52+
}
53+
err = toml.Unmarshal(data, &config)
54+
if err != nil {
55+
fmt.Printf(
56+
"Error parsing config file: %s\nUsing default config instead",
57+
err,
58+
)
59+
return config
60+
}
61+
return config
62+
}

connect/connect.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,22 @@ package connect
33
import (
44
"fmt"
55

6+
"github.com/joshmedeski/sesh/config"
67
"github.com/joshmedeski/sesh/session"
78
"github.com/joshmedeski/sesh/tmux"
89
"github.com/joshmedeski/sesh/zoxide"
910
)
1011

11-
func Connect(choice string, alwaysSwitch bool, command string) error {
12-
session, err := session.Determine(choice)
12+
func Connect(choice string, alwaysSwitch bool, command string, config *config.Config) error {
13+
session, err := session.Determine(choice, config)
1314
if err != nil {
1415
return fmt.Errorf("unable to connect to %q: %w", choice, err)
1516
}
16-
17-
if err := zoxide.Add(session.Path); err != nil {
17+
if err = zoxide.Add(session.Path); err != nil {
1818
return fmt.Errorf("unable to connect to %q: %w", choice, err)
1919
}
20-
21-
return tmux.Connect(
22-
tmux.TmuxSession{Name: session.Name, Path: session.Path},
23-
alwaysSwitch,
24-
command,
25-
)
20+
return tmux.Connect(tmux.TmuxSession{
21+
Name: session.Name,
22+
Path: session.Path,
23+
}, alwaysSwitch, command, session.Path, config)
2624
}

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ module github.com/joshmedeski/sesh
22

33
go 1.21
44

5-
require github.com/urfave/cli/v2 v2.27.1
5+
require (
6+
github.com/pelletier/go-toml/v2 v2.1.1
7+
github.com/stretchr/testify v1.8.4
8+
github.com/urfave/cli/v2 v2.27.1
9+
)
610

711
require (
812
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
913
github.com/davecgh/go-spew v1.1.1 // indirect
1014
github.com/pmezard/go-difflib v1.0.0 // indirect
1115
github.com/russross/blackfriday/v2 v2.1.0 // indirect
12-
github.com/stretchr/objx v0.5.0 // indirect
13-
github.com/stretchr/testify v1.8.4 // indirect
1416
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
1517
gopkg.in/yaml.v3 v3.0.1 // indirect
1618
)

go.sum

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
1-
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
2-
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
31
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
42
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
53
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
64
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
75
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6+
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
7+
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
88
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
99
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1010
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
1111
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
1212
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1313
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
14-
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
1514
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
1615
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
1716
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
1817
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
1918
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
20-
github.com/urfave/cli/v2 v2.27.0 h1:uNs1K8JwTFL84X68j5Fjny6hfANh9nTlJ6dRtZAFAHY=
21-
github.com/urfave/cli/v2 v2.27.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
2219
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
2320
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
24-
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
25-
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
2621
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
2722
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2824
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2925
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
3026
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

session/determine.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package session
33
import (
44
"fmt"
55
"log"
6+
7+
"github.com/joshmedeski/sesh/config"
68
)
79

8-
func Determine(choice string) (s Session, err error) {
10+
func Determine(choice string, config *config.Config) (s Session, err error) {
911
path, err := DeterminePath(choice)
1012
if err != nil {
1113
return s, fmt.Errorf(
@@ -16,7 +18,7 @@ func Determine(choice string) (s Session, err error) {
1618
}
1719
s.Path = path
1820

19-
name := DetermineName(path)
21+
name := DetermineName(path, config)
2022
if name == "" {
2123
log.Fatal("Couldn't determine the session name", err)
2224
return s, fmt.Errorf(

session/name.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"path/filepath"
66
"strings"
77

8+
"github.com/joshmedeski/sesh/config"
89
"github.com/joshmedeski/sesh/git"
910
)
1011

@@ -47,9 +48,9 @@ func nameFromGit(result string) string {
4748
return nameFromGit
4849
}
4950

50-
// TODO: parent directory feature flag detection
51-
func DetermineName(result string) string {
51+
func DetermineName(result string, config *config.Config) string {
5252
name := result
53+
// TODO: parent directory config option detection
5354
pathName := nameFromPath(result)
5455
if pathName != "" {
5556
name = pathName

0 commit comments

Comments
 (0)