add nim implementation
This commit is contained in:
parent
26a3212dad
commit
1561acdb5f
8 changed files with 202 additions and 8 deletions
|
@ -48,7 +48,7 @@
|
|||
pname = "hyprman";
|
||||
version = "${self.shortRev or "dirty"}";
|
||||
src = cleanSource ./.;
|
||||
nimbleDepsHash = "sha256-EQ3gdxIluE+e3Qzqk9v0Q3mBa6nOKR1C1EWyjwSmQSQ=";
|
||||
nimbleDepsHash = "sha256-72FYXiYIgEDX2j/bBADGvwX6+kd+7py0RHTz2WeyXO8=";
|
||||
};
|
||||
});
|
||||
formatter = forAllSystems (pkgs: pkgs.nixfmt-rfc-style);
|
||||
|
|
|
@ -13,4 +13,5 @@ bin = @["hyprman"]
|
|||
requires "nim >= 2.0.8"
|
||||
requires "cligen"
|
||||
requires "yaml"
|
||||
requires "jsony"
|
||||
requires "https://github.com/daylinmorgan/hwylterm#HEAD"
|
||||
|
|
10
nimble.lock
10
nimble.lock
|
@ -21,6 +21,16 @@
|
|||
"sha1": "30f8f61787c36b63d484f3d5e149995fad16c63c"
|
||||
}
|
||||
},
|
||||
"jsony": {
|
||||
"version": "1.1.5",
|
||||
"vcsRevision": "ea811bec7fa50f5abd3088ba94cda74285e93f18",
|
||||
"url": "https://github.com/treeform/jsony",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "6aeb83e7481ca8686396a568096054bc668294df"
|
||||
}
|
||||
},
|
||||
"yaml": {
|
||||
"version": "2.1.1",
|
||||
"vcsRevision": "48a90e36e82bd97457dae87e86efe423dcd3bb40",
|
||||
|
|
135
src/hyprland.nim
Normal file
135
src/hyprland.nim
Normal file
|
@ -0,0 +1,135 @@
|
|||
import std/[os, strformat, strutils, streams, tables, net, sugar]
|
||||
import ./lib
|
||||
export tables
|
||||
import yaml, jsony
|
||||
|
||||
type
|
||||
# Remove effects?
|
||||
HyprlandDefect* = Defect
|
||||
Workspace = object
|
||||
name*: string
|
||||
id*: int
|
||||
Client = object
|
||||
class*: string
|
||||
workspace*: Workspace
|
||||
ActiveWorkspace = object
|
||||
name*: string
|
||||
id*: int
|
||||
Monitor = object
|
||||
activeWorkspace*: ActiveWorkspace
|
||||
id*: int
|
||||
|
||||
|
||||
proc hyprSocketPath(): string =
|
||||
let runtimeDir = getEnv("XDG_RUNTIME_DIR")
|
||||
let instancSig = getEnv("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
result = runtimeDir / "hypr" / instancSig
|
||||
|
||||
let
|
||||
hyprSocket = hyprSocketPath() / ".socket.sock"
|
||||
hyprSocket2 = hyprSocketPath() / ".socket2.sock"
|
||||
|
||||
# TODO: revamp?
|
||||
proc getData[T](msg: string, to: typedesc[T]): T =
|
||||
let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
|
||||
try:
|
||||
socket.connectUnix(hyprSocket)
|
||||
except OSError:
|
||||
raise newException(
|
||||
HyprlandDefect, "Could not connect to Hyprland IPC UNIX path; is Hyprland running?"
|
||||
)
|
||||
|
||||
socket.send msg
|
||||
var recvData: string
|
||||
while true:
|
||||
let response = socket.recv(4096)
|
||||
if response == "": break
|
||||
recvData.add response
|
||||
socket.close() # is this necessary?
|
||||
result = recvData.fromJson(T)
|
||||
|
||||
|
||||
proc getMonitors*(): seq[Monitor] =
|
||||
result = getData("[-j]/monitors", seq[Monitor])
|
||||
|
||||
proc getClients(): seq[Client] =
|
||||
result = getData("[-j]/clients", seq[Client])
|
||||
|
||||
type
|
||||
EwwWorkspace = object
|
||||
icon*, class*: string
|
||||
id*: int
|
||||
|
||||
proc add(ws: var EwwWorkspace, client: Client) =
|
||||
let clientIcon = config.pickIcon(client.class)
|
||||
if ws.icon == config.`no-client`:
|
||||
ws.icon = clientIcon
|
||||
else:
|
||||
ws.icon.add clientIcon
|
||||
|
||||
func openWorkspaces(monitors: seq[Monitor]): seq[int] =
|
||||
for m in monitors:
|
||||
result.add m.activeWorkspace.id
|
||||
|
||||
func setActive(workspaces: seq[EwwWorkspace], m: Monitor): seq[EwwWorkspace] =
|
||||
let id = m.activeWorkspace.id
|
||||
result = workspaces
|
||||
result[id - 1].class.add " ws-button-active-" & $(id)
|
||||
|
||||
proc writeEwwClasses*() =
|
||||
let
|
||||
monitors = getMonitors()
|
||||
clients = getClients()
|
||||
|
||||
var workspaces=
|
||||
collect:
|
||||
for i in 0..<9:
|
||||
EwwWorkspace(
|
||||
icon: config.`no-client`, class: fmt"ws-button-{i+1}", id: i+1
|
||||
)
|
||||
|
||||
for client in clients:
|
||||
let id = client.workspace.id - 1
|
||||
workspaces[id].add client
|
||||
|
||||
for id in openWorkspaces(monitors):
|
||||
workspaces[id - 1].class.add " ws-button-open"
|
||||
|
||||
var ewwClasses =
|
||||
collect:
|
||||
for m in monitors:
|
||||
workspaces.setActive m
|
||||
|
||||
stdout.write (ewwClasses.toJson() & "\n")
|
||||
flushFile stdout
|
||||
|
||||
proc handleHyprEvent(event: string) =
|
||||
let
|
||||
s = event.split(">>", 1)
|
||||
event = s[0]
|
||||
|
||||
# use enum?
|
||||
case event:
|
||||
of "monitoraddedv2":
|
||||
# TODO: open as many bars as necessary depending on num monitors
|
||||
# is it ok to just call open bar again?
|
||||
notify("monitor added")
|
||||
of "openwindow", "workspacev2":
|
||||
writeEwwClasses()
|
||||
else: discard
|
||||
|
||||
|
||||
proc watchHyprland*() =
|
||||
let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
|
||||
try:
|
||||
socket.connectUnix(hyprSocket2)
|
||||
except OSError:
|
||||
raise newException(
|
||||
HyprlandDefect, "Could not connect to Hyprland IPC UNIX path; is Hyprland running?"
|
||||
)
|
||||
writeEwwClasses()
|
||||
while true:
|
||||
var line: string
|
||||
socket.readLine line
|
||||
handleHyprEvent line
|
||||
|
|
@ -1,10 +1,24 @@
|
|||
## hyprman, the hyprland companion
|
||||
|
||||
import ./mako
|
||||
import std/[osproc, strformat]
|
||||
import hwylterm/cligen, cligen
|
||||
import ./[mako,hyprland, lib]# state]
|
||||
|
||||
hwylCli(clCfg)
|
||||
|
||||
proc start() =
|
||||
## launch eww
|
||||
notify("starting eww")
|
||||
for i in 0..<getMonitors().len:
|
||||
let code = execCmd fmt"eww open bar{i}"
|
||||
if code != 0:
|
||||
notify(fmt"failed to open eww bar{i}")
|
||||
|
||||
proc watch() =
|
||||
## watch hyprland events for eww class changes
|
||||
watchHyprland()
|
||||
|
||||
when isMainModule:
|
||||
import hwylterm/cligen, cligen
|
||||
hwylCli(clCfg)
|
||||
const
|
||||
config = //{"config": "path/to/config"}
|
||||
makoHelp = config // {
|
||||
|
@ -13,5 +27,7 @@ when isMainModule:
|
|||
"reverse": "swap notification order"
|
||||
}
|
||||
dispatchMulti(
|
||||
[makoCmd, cmdName = "mako", usage = clCfg.use, help = makoHelp]
|
||||
[makoCmd, cmdName = "mako", usage = clCfg.use, help = makoHelp],
|
||||
[start, usage = clCfg.use],
|
||||
[watch, usage = clCfg.use]
|
||||
)
|
||||
|
|
31
src/lib.nim
Normal file
31
src/lib.nim
Normal file
|
@ -0,0 +1,31 @@
|
|||
import std/[
|
||||
os, osproc, streams, strformat, strutils, tables
|
||||
]
|
||||
export tables
|
||||
import yaml
|
||||
|
||||
proc notify*(message: string) =
|
||||
discard execCmd fmt"notify-send --app-name=hyprman --transient '{message}'"
|
||||
|
||||
type
|
||||
Icons = Table[string, string]
|
||||
Config = object # config vs icons?
|
||||
classes*: Icons
|
||||
`no-client`*: string
|
||||
`default-icon`*: string
|
||||
|
||||
proc loadConfig*(): Config =
|
||||
let configPath = getConfigDir() / "hyprman" / "config.yml"
|
||||
if fileExists(configPath):
|
||||
var s = newFileStream(configPath)
|
||||
load(s, result)
|
||||
|
||||
func pickIcon*(
|
||||
c: Config,
|
||||
class: string
|
||||
): string =
|
||||
for k, v in c.classes:
|
||||
if class in k:
|
||||
result = v
|
||||
|
||||
let config* = loadConfig()
|
|
@ -1,5 +1,6 @@
|
|||
import std/[algorithm, strutils, json, osproc, wordwrap, terminal]
|
||||
import hwylterm
|
||||
|
||||
type
|
||||
MakoNotificationData = object
|
||||
`type`, data: string
|
||||
|
@ -22,7 +23,6 @@ func toHistory(mh: MakoHistory): History =
|
|||
for mn in mh.data[0]:
|
||||
result.notifications.add mn.toNotification()
|
||||
|
||||
|
||||
func filter(h: History, reverse: bool, count: int): History =
|
||||
result.notifications = h.notifications
|
||||
if reverse:
|
||||
|
@ -36,7 +36,6 @@ proc getMakoHistory(): MakoHistory =
|
|||
if errCode != 0: quit output, errCode
|
||||
result = parseJson(output).to(MakoHistory)
|
||||
|
||||
|
||||
proc bb(n: Notification): BbString =
|
||||
template border(style: string): untyped = "[" & style & "]" & "┃ [/]"
|
||||
var raw: string
|
||||
|
|
2
todo.md
2
todo.md
|
@ -1,6 +1,8 @@
|
|||
# hyprman todo's
|
||||
|
||||
- [ ] include in class the 'other' active monitor?
|
||||
- [ ] switch to usu once parser is stable again
|
||||
- [ ] make swww powered wallpaper cycler
|
||||
|
||||
<!-- generated with <3 by daylinmorgan/todo -->
|
||||
|
||||
|
|
Loading…
Reference in a new issue