From ced545f644d2be67877b3b7a5798b11722a95cfd Mon Sep 17 00:00:00 2001 From: Asmir A Date: Thu, 26 Oct 2023 22:04:01 +0200 Subject: [PATCH] project: add skelet --- .gitignore | 64 +++++++++++++++++++++++++++++++++++++++ flake.lock | 26 ++++++++++++++++ flake.nix | 71 +++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 ++ main.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 252 insertions(+) create mode 100644 .gitignore create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 go.mod create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe97981 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Created by https://www.toptal.com/developers/gitignore/api/go,vim,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=go,vim,linux + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +result + +# End of https://www.toptal.com/developers/gitignore/api/go,vim,linux diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f5a0e36 --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1698134075, + "narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8efd5d1e283604f75a808a20e6cde0ef313d07d4", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4092048 --- /dev/null +++ b/flake.nix @@ -0,0 +1,71 @@ +{ + description = "A simple Go program for switching windows on Sway wm"; + + # Nixpkgs / NixOS version to use. + inputs.nixpkgs.url = "nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: + let + + # to work with older version of flakes + lastModifiedDate = self.lastModifiedDate or self.lastModified or "19700101"; + + # Generate a user-friendly version number. + version = builtins.substring 0 8 lastModifiedDate; + + # System types to support. + supportedSystems = [ "x86_64-linux" "aarch64-linux" ]; + + # Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'. + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + + # Nixpkgs instantiated for supported system types. + nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); + + in + { + + # Provide some binary packages for selected system types. + packages = forAllSystems (system: + let + pkgs = nixpkgsFor.${system}; + in + { + swaysw = pkgs.buildGoModule { + pname = "swaysw"; + inherit version; + # In 'nix develop', we don't need a copy of the source tree + # in the Nix store. + src = ./.; + + # This hash locks the dependencies of this package. It is + # necessary because of how Go requires network access to resolve + # VCS. See https://www.tweag.io/blog/2021-03-04-gomod2nix/ for + # details. Normally one can build with a fake sha256 and rely on native Go + # mechanisms to tell you what the hash should be or determine what + # it should be "out-of-band" with other tooling (eg. gomod2nix). + # To begin with it is recommended to set this, but one must + # remeber to bump this hash when your dependencies change. + vendorSha256 = null; + + #vendorSha256 = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; + }; + }); + + # Add dependencies that are only needed for development + devShells = forAllSystems (system: + let + pkgs = nixpkgsFor.${system}; + in + { + default = pkgs.mkShell { + buildInputs = with pkgs; [ go gopls gotools go-tools wofi ]; + }; + }); + + # The default package for 'nix build'. This makes sense if the + # flake provides only one package or there is a clear "main" + # package. + defaultPackage = forAllSystems (system: self.packages.${system}.swaysw); + }; +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3c003c0 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module example/swaysw + +go 1.20 diff --git a/main.go b/main.go new file mode 100644 index 0000000..103f047 --- /dev/null +++ b/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os/exec" + "strings" +) + +type tree struct { + Id int `json:"id"` + Name string `json:"name,omitempty"` + AppId string `json:"app_id,omitempty"` + Type string `json:"type,omitempty"` + Nodes []tree `json:"nodes,omitempty"` + FloatingNodes []tree `json:"floating_nodes,omitempty"` +} + +type window struct { + Id int + AppIdAndName string +} + +func flatten(in tree, windows *[]window) { + if in.Name != "" && (in.Type == "con" || in.Type == "floating_con") { + *windows = append(*windows, window{in.Id, in.AppId + " " + in.Name}) + } + for _, node := range append(in.Nodes, in.FloatingNodes...) { + flatten(node, windows) + } +} + +func getWindowNames(windows []window) string { + var windowNames []string + for _, idAndName := range windows { + windowNames = append(windowNames, idAndName.AppIdAndName) + } + return strings.Join(windowNames, "\n") +} + +func selectWithWofi(windows string) string { + cmd := exec.Command("wofi", "-i", "-d") + cmd.Stdin = strings.NewReader(windows) + stdout, err := cmd.Output() + if err != nil { + log.Fatal(err) + } + return strings.TrimSpace(string(stdout)) +} + +func findWindowId(windowName string, windows []window) int { + for _, window := range windows { + if windowName == window.AppIdAndName { + return window.Id + } + } + log.Fatal("Invalid Window Name") + return -1 +} + +func switchToWindow(id int) { + arg1 := fmt.Sprintf("[con_id=%d]", id) + cmd := exec.Command("swaymsg", arg1, "focus") + cmd.Start() +} + +func main() { + + cmd := exec.Command("swaymsg", "-r", "-t", "get_tree") + stdout, err := cmd.Output() + if err != nil { + log.Fatal(err) + return + } + + var swaymsg_output tree + if err := json.Unmarshal(stdout, &swaymsg_output); err != nil { + log.Fatal(err) + } + + var windows []window + flatten(swaymsg_output, &windows) + + selected := selectWithWofi(getWindowNames(windows)) + windowId := findWindowId(selected, windows) + switchToWindow(windowId) +}