summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-08-25 10:02:14 -0500
committerJeff Carr <[email protected]>2025-08-25 10:02:14 -0500
commit6dd0052dcf530af22a43ca02a8e0b6cebcc383e0 (patch)
tree3bc6095ae4304c0b75c4628582fb2f903c4cbb7b
parent9d5bd8d5b92fc91a6ff03398cd9f338dce4ca6b4 (diff)
restructor code
-rw-r--r--Makefile6
-rw-r--r--README.md25
-rw-r--r--argv.go36
-rw-r--r--argvAutoshell.go87
-rw-r--r--common.go102
-rw-r--r--exit.go22
-rw-r--r--launch_terminal.go98
-rw-r--r--main.go55
-rw-r--r--structs.go17
-rw-r--r--sync_terminals.go34
10 files changed, 350 insertions, 132 deletions
diff --git a/Makefile b/Makefile
index 3a70645..035f59c 100644
--- a/Makefile
+++ b/Makefile
@@ -3,13 +3,15 @@
VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d)
+default: goimports verbose
+
build:
GO111MODULE=off go build \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
- ./xstartplacement
+ ./startxplacement
verbose:
- GO111MODULE=off go build -v -x \
+ GO111MODULE=off go install -v -x \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
install:
diff --git a/README.md b/README.md
index 735fb1b..564f8d5 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,24 @@
-# devils pie code to try to fix window placement
+# This is an attempt to redo 'startx' not as a bash script this time
+
+GOALS:
+
+ * use a protobuf TEXT config file
+ * store global file in ~/etc/startx.text
+ * store user config file in ~/.config/startx.text
+ * parse additional settings from ~/.config/startx.d/
+ * restore the geometry of the apps
+ * make a GUI save/edit/restore tool
+
+CURRENTLY WORKING:
+
+ * works with x windows
+ * restores mate-terminal on debian
+
+TODO:
+
+ * wayland support
+ * other programs like firefox & keepass
+ * actually execute from lightdm
+ * run underneath mate-session
+ * run underneath all the other WM
+ * rename binary 'startx'
diff --git a/argv.go b/argv.go
new file mode 100644
index 0000000..8f1971e
--- /dev/null
+++ b/argv.go
@@ -0,0 +1,36 @@
+// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
+// Use of this source code is governed by the GPL 3.0
+
+package main
+
+/*
+ this parses the command line arguements using alex flint's go-arg
+*/
+
+var argv args
+
+type args struct {
+ Restore string `arg:"--restore" help:"restore terminal windows from a config file"`
+ Save *EmptyCmd `arg:"subcommand:save" help:"save current window geometries to the your config file"`
+ Dump *EmptyCmd `arg:"subcommand:dump" help:"show your current window geometries"`
+ Force bool `arg:"--force" help:"try to strong arm things"`
+ Verbose bool `arg:"--verbose" help:"show more output"`
+ Bash bool `arg:"--bash" help:"generate bash completion"`
+ BashAuto []string `arg:"--auto-complete" help:"todo: move this to go-arg"`
+}
+
+type EmptyCmd struct {
+}
+
+func (args) Version() string {
+ return ARGNAME + " " + VERSION + " Built on " + BUILDTIME
+}
+
+func (a args) Description() string {
+ return `
+startxplacment -- run this after 'startx' to restore all your apps
+
+will attempt to launch your terminal windows on the right Workspaces
+and with the right geometries. TODO: restore the bash working paths
+ `
+}
diff --git a/argvAutoshell.go b/argvAutoshell.go
new file mode 100644
index 0000000..85d841b
--- /dev/null
+++ b/argvAutoshell.go
@@ -0,0 +1,87 @@
+// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
+// Use of this source code is governed by the GPL 3.0
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+/*
+ handles shell autocomplete
+*/
+
+// used for shell auto completion
+// var ARGNAME string = "forge" // todo: get this from $0 ?
+
+func deleteMatch() {
+ // f := forgedb.InitSimple()
+ fmt.Println("go.wit.com/lib/gui/repostatus todo: need to do this")
+}
+
+func (args) doBashAuto() {
+ argv.doBashHelp()
+ switch argv.BashAuto[0] {
+ case "dump":
+ fmt.Println("--terminals")
+ default:
+ if argv.BashAuto[0] == ARGNAME {
+ // list the subcommands here
+ fmt.Println("--restore save dump")
+ }
+ }
+ os.Exit(0)
+}
+
+// prints help to STDERR // TODO: move everything below this to go-args
+func (args) doBashHelp() {
+ if argv.BashAuto[1] != "''" {
+ // if this is not blank, then the user has typed something
+ return
+ }
+ if argv.BashAuto[0] != ARGNAME {
+ // if this is not the name of the command, the user already started doing something
+ return
+ }
+ if argv.BashAuto[0] == ARGNAME {
+ me.pp.WriteHelp(os.Stderr)
+ return
+ }
+ fmt.Fprintln(os.Stderr, "")
+ fmt.Fprintln(os.Stderr, "something went wrong with the GO args package")
+ fmt.Fprintln(os.Stderr, "")
+}
+
+// complete -F forge --bash forge
+func (args) doBash() {
+ fmt.Println("# add this in your bashrc:")
+ fmt.Println("")
+ fmt.Println("# todo: add this to go-arg as a 'hidden' go-arg option --bash")
+ fmt.Println("#")
+ fmt.Println("# Put the below in the file: ~/.local/share/bash-completion/completions/" + ARGNAME)
+ fmt.Println("#")
+ fmt.Println("# todo: make this output work/parse with:")
+ fmt.Println("# complete -C " + ARGNAME + " --bash go")
+ fmt.Println("")
+ fmt.Println("_" + ARGNAME + "_complete()")
+ fmt.Println("{")
+ fmt.Println(" # sets local to this func vars")
+ fmt.Println(" local cur prev all")
+ fmt.Println(" cur=${COMP_WORDS[COMP_CWORD]}")
+ fmt.Println(" prev=${COMP_WORDS[COMP_CWORD-1]}")
+ fmt.Println(" all=${COMP_WORDS[@]}")
+ fmt.Println("")
+ fmt.Println(" # this is where we generate the go-arg output")
+ fmt.Println(" GOARGS=$(" + ARGNAME + " --auto-complete $prev \\'$cur\\' $all)")
+ fmt.Println("")
+ fmt.Println(" # this compares the command line input from the user")
+ fmt.Println(" # to whatever strings we output")
+ fmt.Println(" COMPREPLY=( $(compgen -W \"$GOARGS\" -- $cur) ) # THIS WORKS")
+ fmt.Println(" return 0")
+ fmt.Println("}")
+ fmt.Println("complete -F _" + ARGNAME + "_complete " + ARGNAME)
+ fmt.Println("")
+ fmt.Println("# copy and paste the above into your bash shell should work")
+ os.Exit(0)
+}
diff --git a/common.go b/common.go
new file mode 100644
index 0000000..202111c
--- /dev/null
+++ b/common.go
@@ -0,0 +1,102 @@
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+)
+
+// Helper functions
+func getWindowList() (map[string]string, error) {
+ cmd := exec.Command("wmctrl", "-l")
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ if err := cmd.Run(); err != nil {
+ return nil, err
+ }
+ windows := make(map[string]string)
+ scanner := bufio.NewScanner(&out)
+ for scanner.Scan() {
+ line := scanner.Text()
+ fields := strings.Fields(line)
+ if len(fields) > 0 {
+ windows[fields[0]] = strings.Join(fields[3:], " ")
+ }
+ }
+ return windows, nil
+}
+
+// findNewWindow compares two maps of windows and returns the ID of the new window.
+func findNewWindow(before, after map[string]string) string {
+ for id := range after {
+ if _, ok := before[id]; !ok {
+ return id
+ }
+ }
+ return ""
+}
+
+// parseConfig remains the same as before.
+func parseConfig(filePath string) ([]WindowConfig, error) {
+ file, err := os.Open(filePath)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var configs []WindowConfig
+ scanner := bufio.NewScanner(file)
+ var currentConfig WindowConfig
+
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return nil, fmt.Errorf("could not get user home directory: %w", err)
+ }
+
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, " Title: ") {
+ title := strings.TrimSpace(strings.TrimPrefix(line, " Title: "))
+ currentConfig.Title = title
+ parts := strings.SplitN(title, ": ", 2)
+ if len(parts) == 2 {
+ path := parts[1]
+ if strings.HasPrefix(path, "~") {
+ path = filepath.Join(homeDir, path[1:])
+ }
+ currentConfig.Path = path
+ }
+ } else if strings.HasPrefix(line, " Geometry: ") {
+ geomStr := strings.TrimSpace(strings.TrimPrefix(line, " Geometry: "))
+ var x, y, w, h string
+ _, err := fmt.Sscanf(geomStr, "X=%s Y=%s Width=%s Height=%s", &x, &y, &w, &h)
+ if err == nil {
+ x = strings.TrimSuffix(x, ",")
+ y = strings.TrimSuffix(y, ",")
+ w = strings.TrimSuffix(w, ",")
+ currentConfig.Geometry = fmt.Sprintf("%sx%s+%s+%s", w, h, x, y)
+ }
+ } else if strings.HasPrefix(line, " Workspace: ") {
+ currentConfig.Workspace = strings.TrimSpace(strings.TrimPrefix(line, " Workspace: "))
+ } else if line == "---" {
+ if currentConfig.Path != "" {
+ configs = append(configs, currentConfig)
+ }
+ currentConfig = WindowConfig{} // Reset for the next entry
+ }
+ }
+
+ if currentConfig.Path != "" {
+ configs = append(configs, currentConfig)
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return configs, nil
+}
diff --git a/exit.go b/exit.go
new file mode 100644
index 0000000..ad6195b
--- /dev/null
+++ b/exit.go
@@ -0,0 +1,22 @@
+// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
+// Use of this source code is governed by the GPL 3.0
+
+package main
+
+import (
+ "os"
+
+ "go.wit.com/log"
+)
+
+func okExit(thing string) {
+ if thing != "" {
+ log.Info("regex exit:", thing, "ok")
+ }
+ os.Exit(0)
+}
+
+func badExit(err error) {
+ log.Info("regex failed: ", err)
+ os.Exit(-1)
+}
diff --git a/launch_terminal.go b/launch_terminal.go
index be3a5d7..7ee72fe 100644
--- a/launch_terminal.go
+++ b/launch_terminal.go
@@ -1,12 +1,9 @@
package main
import (
- "bufio"
- "bytes"
"fmt"
"os"
"os/exec"
- "path/filepath"
"strings"
"time"
)
@@ -19,7 +16,7 @@ type WindowConfig struct {
Workspace string
}
-func main() {
+func doLaunch() {
// 1. Get current working directory.
pwd, err := os.Getwd()
if err != nil {
@@ -28,7 +25,6 @@ func main() {
}
// 2. Read and parse the configuration file.
- configFile := "/home/jcarr/go/src/gemini/xstartplacement.out"
configs, err := parseConfig(configFile)
if err != nil {
fmt.Printf("Failed to parse config file '%s': %v\n", configFile, err)
@@ -108,95 +104,3 @@ func main() {
fmt.Println("Window setup complete.")
}
}
-
-// getWindowList returns a map of window IDs to their titles.
-func getWindowList() (map[string]string, error) {
- cmd := exec.Command("wmctrl", "-l")
- var out bytes.Buffer
- cmd.Stdout = &out
- if err := cmd.Run(); err != nil {
- return nil, err
- }
-
- windows := make(map[string]string)
- scanner := bufio.NewScanner(&out)
- for scanner.Scan() {
- line := scanner.Text()
- fields := strings.Fields(line)
- if len(fields) > 0 {
- windows[fields[0]] = strings.Join(fields[3:], " ")
- }
- }
- return windows, nil
-}
-
-// findNewWindow compares two maps of windows and returns the ID of the new window.
-func findNewWindow(before, after map[string]string) string {
- for id := range after {
- if _, ok := before[id]; !ok {
- return id
- }
- }
- return ""
-}
-
-// parseConfig remains the same as before.
-func parseConfig(filePath string) ([]WindowConfig, error) {
- file, err := os.Open(filePath)
- if err != nil {
- return nil, err
- }
- defer file.Close()
-
- var configs []WindowConfig
- scanner := bufio.NewScanner(file)
- var currentConfig WindowConfig
-
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return nil, fmt.Errorf("could not get user home directory: %w", err)
- }
-
- for scanner.Scan() {
- line := scanner.Text()
- if strings.HasPrefix(line, " Title: ") {
- title := strings.TrimSpace(strings.TrimPrefix(line, " Title: "))
- currentConfig.Title = title
- parts := strings.SplitN(title, ": ", 2)
- if len(parts) == 2 {
- path := parts[1]
- if strings.HasPrefix(path, "~") {
- path = filepath.Join(homeDir, path[1:])
- }
- currentConfig.Path = path
- }
- } else if strings.HasPrefix(line, " Geometry: ") {
- geomStr := strings.TrimSpace(strings.TrimPrefix(line, " Geometry: "))
- var x, y, w, h string
- _, err := fmt.Sscanf(geomStr, "X=%s Y=%s Width=%s Height=%s", &x, &y, &w, &h)
- if err == nil {
- x = strings.TrimSuffix(x, ",")
- y = strings.TrimSuffix(y, ",")
- w = strings.TrimSuffix(w, ",")
- currentConfig.Geometry = fmt.Sprintf("%sx%s+%s+%s", w, h, x, y)
- }
- } else if strings.HasPrefix(line, " Workspace: ") {
- currentConfig.Workspace = strings.TrimSpace(strings.TrimPrefix(line, " Workspace: "))
- } else if line == "---" {
- if currentConfig.Path != "" {
- configs = append(configs, currentConfig)
- }
- currentConfig = WindowConfig{} // Reset for the next entry
- }
- }
-
- if currentConfig.Path != "" {
- configs = append(configs, currentConfig)
- }
-
- if err := scanner.Err(); err != nil {
- return nil, err
- }
-
- return configs, nil
-}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..26bba0b
--- /dev/null
+++ b/main.go
@@ -0,0 +1,55 @@
+// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
+// Use of this source code is governed by the GPL 3.0
+
+package main
+
+// An app to submit patches for the 30 GO GUI repos
+
+import (
+ "os"
+
+ "go.wit.com/dev/alexflint/arg"
+ "go.wit.com/gui"
+ "go.wit.com/log"
+)
+
+// sent via -ldflags
+var VERSION string
+var BUILDTIME string
+
+// used for shell auto completion
+var ARGNAME string = "startxplacment"
+
+// using this for now. triggers config save
+var configSave bool
+
+var configFile string = "/home/jcarr/.config/startxplacement.out"
+
+func main() {
+ me = new(mainType)
+ gui.InitArg()
+ me.pp = arg.MustParse(&argv)
+
+ if argv.Bash {
+ argv.doBash()
+ os.Exit(0)
+ }
+ if len(argv.BashAuto) != 0 {
+ argv.doBashAuto()
+ os.Exit(0)
+ }
+
+ if argv.Dump != nil {
+ // doDump()
+ log.Info("dump here")
+ okExit("")
+ }
+
+ if argv.Restore != "" {
+ log.Info("restore here")
+ okExit("")
+ }
+
+ // doGui()
+ okExit("")
+}
diff --git a/structs.go b/structs.go
new file mode 100644
index 0000000..178a187
--- /dev/null
+++ b/structs.go
@@ -0,0 +1,17 @@
+// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
+// Use of this source code is governed by the GPL 3.0
+
+package main
+
+import (
+ "go.wit.com/dev/alexflint/arg"
+ "go.wit.com/gui"
+)
+
+var me *mainType
+
+// this app's variables
+type mainType struct {
+ pp *arg.Parser // for parsing the command line args. Yay to alexf lint!
+ myGui *gui.Node // the gui toolkit handle
+}
diff --git a/sync_terminals.go b/sync_terminals.go
index 2c557ba..b115d8f 100644
--- a/sync_terminals.go
+++ b/sync_terminals.go
@@ -26,9 +26,8 @@ type CurrentState struct {
Path string
}
-func main() {
+func doSync() {
// 1. Read the desired state from the config file.
- configFile := "/home/jcarr/go/src/gemini/xstartplacement.out"
desiredStates, err := parseDesiredState(configFile)
if err != nil {
fmt.Printf("Error parsing config file: %v\n", err)
@@ -105,7 +104,7 @@ func launchTerminal(state DesiredState) {
fmt.Printf("Successfully launched terminal for %s\n", state.Path)
}
-// parseDesiredState reads the xstartplacement.out file.
+// parseDesiredState reads the startxplacement.out file.
func parseDesiredState(filePath string) ([]DesiredState, error) {
file, err := os.Open(filePath)
if err != nil {
@@ -197,32 +196,3 @@ func getCurrentState() ([]CurrentState, error) {
}
return states, nil
}
-
-// Helper functions
-func getWindowList() (map[string]string, error) {
- cmd := exec.Command("wmctrl", "-l")
- var out bytes.Buffer
- cmd.Stdout = &out
- if err := cmd.Run(); err != nil {
- return nil, err
- }
- windows := make(map[string]string)
- scanner := bufio.NewScanner(&out)
- for scanner.Scan() {
- line := scanner.Text()
- fields := strings.Fields(line)
- if len(fields) > 0 {
- windows[fields[0]] = strings.Join(fields[3:], " ")
- }
- }
- return windows, nil
-}
-
-func findNewWindow(before, after map[string]string) string {
- for id := range after {
- if _, ok := before[id]; !ok {
- return id
- }
- }
- return ""
-} \ No newline at end of file