diff --git a/.gitignore b/.gitignore index 46bdf95..f1b3f65 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ *.out # Vendor -vendor/ \ No newline at end of file +vendor/ + +btops diff --git a/README.md b/README.md index a9bf96a..53f1a10 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,24 @@ bspwm desktop management that supports dymanic appending, removing, and renaming ## Introduction -Often times a workflow for a given day can't be defined by a set number of desktops with constant names. Btops enables you to define your workspaces based on what you're doing so you don't have worry about things like putting your applications in their respective desktops, running out of desktops, or leaving desktops unused and empty. +Often times a workflow for a given day can't be defined by a set number of desktops with constant names. Btops enables you to define your workspaces based on what you're doing so you don't have to worry about things like putting your applications in their respective desktops, running out of desktops, or leaving desktops unused and empty. ## Examples -#### Dynamic with classified renamers -[![btops dynamic](https://thumbs.gfycat.com/CourteousHeavyGibbon-size_restricted.gif)](https://gfycat.com/CourteousHeavyGibbon) - -#### [Minmax](https://github.com/cmschuetz/btops/blob/master/examples/minmax.toml) -[![btops minmax](https://thumbs.gfycat.com/HairyRewardingIncatern-size_restricted.gif)](https://gfycat.com/HairyRewardingIncatern) - +- [Dynamic with classified renamers](https://github.com/cmschuetz/btops/blob/master/examples/classified.toml)Add commentMore actions +- [Minmax with numeric renamer](https://github.com/cmschuetz/btops/blob/master/examples/minmax.toml) +- [Static](https://github.com/cmschuetz/btops/blob/master/examples/static.toml) ## Configuration -btops supports config files in toml, json, and yaml format. It'll look in the following places for config files: +btops supports config files in toml, json, and yaml format. It'll look in the following places for config files: ``` $XDG_CONFIG_HOME/btops/config.* ~/.config/btops/config.* ``` -Below are the different configuration options available. Please look at [examples](https://github.com/cmschuetz/btops/tree/master/examples) for example usage +Below are the different configuration options available. Please look at [examples](https://github.com/cmschuetz/btops/tree/master/examples) for example usage ### Configuration Options @@ -33,9 +30,10 @@ Below are the different configuration options available. Please look at [exampl | min | Int | Minimum number of desktops per monitor | 1 | | max | Int | Maximum number of desktops per monitor | infinity | | remove-empty | Bool | Removes empty desktops | true | +| remove-focused | Bool | Removes focused desktops | false | | append-when-occupied | Bool | Appends a new desktop when all other desktops are occupied | true | | watch-config | Bool | Reload btops on next event when configuration changes | true | -| renamers | []String | Order of [renamers](#renamers) to use for renaming desktops. If a given renamer is unable to rename a desktop, it cascades to the next renmaer | ["numeric"] +| renamers | []String | Order of [renamers](#renamers) to use for renaming desktops. If a given renamer is unable to rename a desktop, it cascades to the next renmaer | ["numeric"] | | names | Names | [Names configuration object](#names) | {} | ### Renamers @@ -55,12 +53,12 @@ names configuration object | ------ | ---- | ----------- | | constant | String | A single string that the constant renamer uses to rename desktops | | static | []String | A list of desktop names that the static renamer uses to rename desktops | -| classified | []{ classification: []String (clients) } | An array of objects that match client names with a given classification. If multiple classifications are matched, the first will be used as the desktop name +| classified | []{ classification: []String (clients) } | An array of objects that match client names with a given classification. If multiple classifications are matched, the first will be used as the desktop name | ## Installation -- Ensure [go](https://golang.org/) is installed and your [$GOPATH](https://github.com/golang/go/wiki/GOPATH) is set -- `go get github.com/cmschuetz/btops` +- Ensure [Go](https://go.dev/) is installed and your [$GOPATH](https://go.dev/wiki/GOPATH) is set +- `go install github.com/cmschuetz/btops@latest` - run `$GOPATH/bin/btops` ### Arch Linux diff --git a/config/config.go b/config/config.go index 3266fe8..34f277f 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type Config struct { Min int Max int RemoveEmpty bool `mapstructure:"remove-empty"` + RemoveFocused bool `mapstructure:"remove-focused"` AppendWhenOccupied bool `mapstructure:"append-when-occupied"` WatchConfig bool `mapstructure:"watch-config"` configChangeC chan bool @@ -89,6 +90,7 @@ func newDefaultConfig() *viper.Viper { c.SetDefault("min", 1) c.SetDefault("max", math.MaxInt64) c.SetDefault("remove-empty", true) + c.SetDefault("remove-focused", true) c.SetDefault("append-when-occupied", true) c.SetDefault("renamers", []string{numeric}) c.SetDefault("watch-config", true) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b4edb59 --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module github.com/cmschuetz/btops + +go 1.21.6 + +require ( + github.com/fsnotify/fsnotify v1.4.2 + github.com/spf13/viper v1.0.0 +) + +require ( + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect + github.com/magiconair/properties v1.7.3 // indirect + github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e // indirect + github.com/pelletier/go-toml v1.0.1 // indirect + github.com/spf13/afero v1.0.0 // indirect + github.com/spf13/cast v1.1.0 // indirect + github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 // indirect + github.com/spf13/pflag v1.0.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc // indirect + golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fb277e1 --- /dev/null +++ b/go.sum @@ -0,0 +1,43 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +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/fsnotify/fsnotify v1.4.2 h1:v5tKwtf2hNhBV24eNYfQ5UmvFOGlOCmRqk7/P1olxtk= +github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb h1:1OvvPvZkn/yCQ3xBcM8y4020wdkMXPHLB4+NfoGWh4U= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.7.3 h1:6AOjgCKyZFMG/1yfReDPDz3CJZPxnYk7DGmj2HtyF24= +github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e h1:PtGHLB3CX3TFPcksODQMxncoeQKWwCgTg0bJ40VLJP4= +github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.0.1 h1:0nx4vKBl23+hEaCOV1mFhKS9vhhBtFYWC7rQY0vJAyE= +github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.0.0 h1:Z005C09nPzwTTsDRJCQBVnpTU0bjTr/NhyWLj1nSPP4= +github.com/spf13/afero v1.0.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.1.0 h1:0Rhw4d6C8J9VPu6cjZLIhZ8+aAOHcDvGeKn+cq5Aq3k= +github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 h1:zBoLErXXAvWnNsu+pWkRYl6Cx1KXmIfAVsIuYkPN6aY= +github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.0 h1:oaPbdDe/x0UncahuwiPxW1GYJyilRAdsPnq3e1yaPcI= +github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= +github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc h1:pt5pMsz4A/sZRT17MOvX/nidmCt7n6ILLJBkNh5QqC8= +golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 h1:OxMYHd6bm+jH+TI7NBCb/CaYk6pMJnBC8GIzIi68Hk4= +golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab h1:yZ6iByf7GKeJ3gsd1Dr/xaj1DyJ//wxKX1Cdh8LhoAw= +gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/handlers.go b/handlers/handlers.go index 41750a4..af85eb1 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -134,12 +134,20 @@ func (r RemoveHandler) ShouldHandle() bool { func (r RemoveHandler) Handle(m *monitors.Monitors) bool { for _, monitor := range *m { + if len(monitor.EmptyDesktops()) == 1 { + continue + } + for _, desktop := range monitor.EmptyDesktops() { - if *desktop == monitor.Desktops[len(monitor.Desktops)-1] { + if r.config.Min >= len(monitor.Desktops) { continue } - if r.config.Min >= len(monitor.Desktops) { + if !r.config.RemoveFocused && monitor.FocusedDesktopId == desktop.Id { + continue + } + + if *desktop == monitor.Desktops[len(monitor.Desktops)-1] && !(monitor.Desktops[len(monitor.Desktops)-2].IsEmpty()) { continue } diff --git a/monitors/monitors.go b/monitors/monitors.go index 2c07098..ca3460b 100644 --- a/monitors/monitors.go +++ b/monitors/monitors.go @@ -15,6 +15,7 @@ type bspwmState struct { type Monitor struct { Name string Id int + FocusedDesktopId int Desktops []Desktop }