package main import ( "bufio" "bytes" "fmt" "os" "os/exec" "path/filepath" "strings" "time" ) // WindowConfig holds the configuration for a single terminal window. type WindowConfig struct { Title string Path string Geometry string // In WIDTHxHEIGHT+X+Y format Workspace string } func main() { // 1. Get current working directory. pwd, err := os.Getwd() if err != nil { fmt.Println("Failed to get current directory:", err) return } // 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) return } // 3. Find the best matching configuration for the current directory. var bestMatch *WindowConfig longestPrefix := 0 for i, config := range configs { if strings.HasPrefix(pwd, config.Path) { if len(config.Path) > longestPrefix { longestPrefix = len(config.Path) bestMatch = &configs[i] } } } if bestMatch == nil { fmt.Printf("No configuration found for directory: %s\n", pwd) return } targetConfig := bestMatch fmt.Printf("Found matching configuration for path: %s\n", targetConfig.Path) // 4. Get the list of windows before launching the new terminal. windowsBefore, err := getWindowList() if err != nil { fmt.Println("Failed to get initial window list:", err) return } // 5. Launch mate-terminal. geomString := targetConfig.Geometry cmd := exec.Command("mate-terminal", "--geometry", geomString) if err := cmd.Start(); err != nil { fmt.Println("Failed to start mate-terminal:", err) return } fmt.Printf("Launched mate-terminal with geometry %s\n", geomString) // 6. Find the new window by comparing the window lists. var newWindowID string for i := 0; i < 10; i++ { time.Sleep(500 * time.Millisecond) windowsAfter, err := getWindowList() if err != nil { fmt.Println("Failed to get updated window list:", err) continue } newWindowID = findNewWindow(windowsBefore, windowsAfter) if newWindowID != "" { break } } if newWindowID == "" { fmt.Println("Could not find the new terminal window.") return } fmt.Printf("Found new window with ID: %s\n", newWindowID) // 7. Move the window to the correct workspace. cmd = exec.Command("wmctrl", "-i", "-r", newWindowID, "-t", targetConfig.Workspace) if err := cmd.Run(); err != nil { fmt.Println("Failed to move window to workspace:", err) } else { fmt.Printf("Moved window to workspace %s\n", targetConfig.Workspace) } // 8. Set the final window title. finalTitle := fmt.Sprintf("jcarr@framebook: %s", pwd) cmd = exec.Command("wmctrl", "-i", "-r", newWindowID, "-T", finalTitle) if err := cmd.Run(); err != nil { fmt.Println("Failed to set final window title:", err) } else { 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 }