200 lines
5.5 KiB
Nim
200 lines
5.5 KiB
Nim
import base
|
|
import std/[osproc,json,strutils]
|
|
|
|
const I3_WORKSPACES = "i3-msg -t get_workspaces"
|
|
const I3_TREE = "i3-msg -t get_tree"
|
|
const VISIBLE = "#"
|
|
const URGENT = "!"
|
|
const FOCUSED = "%"
|
|
|
|
type
|
|
Workspace = object
|
|
num: int
|
|
name: string
|
|
focused: bool
|
|
visible: bool
|
|
output: string
|
|
urgent: bool
|
|
display_string: string
|
|
apps: seq[string]
|
|
applications: seq[Application]
|
|
application: Application
|
|
Application = object
|
|
title: string
|
|
class: string
|
|
focused: bool
|
|
urgent: bool
|
|
|
|
var my_workspaces: seq[Workspace]
|
|
var current_workspace: int = 0
|
|
|
|
proc showWorkspaces()
|
|
|
|
proc buildString(ws: Workspace): string =
|
|
var str = $ws.num & " |"
|
|
# if ws.urgent or ws.application.urgent:
|
|
if ws.application.urgent:
|
|
str &= URGENT
|
|
else:
|
|
str &= " "
|
|
if ws.focused or ws.application.focused:
|
|
current_workspace = ws.num
|
|
str &= FOCUSED
|
|
# elif ws.visible:
|
|
# str &= VISIBLE
|
|
else:
|
|
str &= " "
|
|
str &= "| " & ws.output & " | "
|
|
if ws.application.class != "":
|
|
str &= ws.application.class & " " & ws.application.title & " | "
|
|
else:
|
|
str = ""
|
|
# for app in ws.applications:
|
|
# str &= app.class & " " & app.title & " | "
|
|
return str
|
|
|
|
proc findWorkspace(workspace: string): Workspace =
|
|
for ws in my_workspaces:
|
|
if workspace == ws.display_string:
|
|
return ws
|
|
|
|
proc switchWorkspace(workspace: string) =
|
|
if workspace.contains("%"):
|
|
return
|
|
let ws = findWorkspace(workspace)
|
|
if ws.num == current_workspace:
|
|
return
|
|
let cmd = "i3-msg workspace " & $ws.num
|
|
discard execCmd(cmd)
|
|
showWorkspaces()
|
|
|
|
# proc getApplications(node: JsonNode): (seq[string],bool) =
|
|
# var apps: seq[string] = @[]
|
|
# var focused = false
|
|
# for item in node["nodes"].getElems():
|
|
# var name = ""
|
|
# if item["focused"].getBool():
|
|
# focused = true
|
|
# if item{"window_properties"} != nil :
|
|
# let prop = item["window_properties"]
|
|
# name = prop["class"].getStr()
|
|
# name &= " " & prop["title"].getStr()
|
|
# echo "Adding application : " & name
|
|
# apps.add(name)
|
|
# return (apps, focused)
|
|
#
|
|
proc getApplication(node: JsonNode, ws: Workspace = Workspace()): Application =
|
|
var app = Application()
|
|
let window = node["window_properties"]
|
|
app.title = window["title"].getStr()
|
|
app.class = window["class"].getStr()
|
|
app.focused = node["focused"].getBool()
|
|
app.urgent = node["urgent"].getBool()
|
|
#echo ws.num
|
|
#echo app.title & " " & app.class
|
|
return app
|
|
|
|
# proc findWorkspaces(node: JsonNode) =
|
|
# for channel in node["nodes"].getElems():
|
|
# case channel["type"].getStr():
|
|
# of "workspace":
|
|
# if channel["output"].getStr() == "__i3":
|
|
# continue
|
|
# let w = channel
|
|
# let apps = getApplications(channel)
|
|
# var space = Workspace(
|
|
# num: w["num"].getInt(),
|
|
# name: w["name"].getStr(),
|
|
# focused: apps[1],
|
|
# #visible: w["visible"].getBool(),
|
|
# urgent: w["urgent"].getBool(),
|
|
# output: w["output"].getStr(),
|
|
# apps: apps[0]
|
|
# )
|
|
# space.display_string = buildString(space)
|
|
# my_workspaces.add(space)
|
|
# else:
|
|
# echo "finding workspaces..."
|
|
# findWorkspaces(channel)
|
|
# return
|
|
|
|
proc newWorkspace(node: JsonNode): Workspace =
|
|
return Workspace(
|
|
num: node["num"].getInt(),
|
|
name: node["name"].getStr(),
|
|
focused: node["focused"].getBool(),
|
|
#visible: w["visible"].getBool(),
|
|
urgent: node["urgent"].getBool(),
|
|
output: node["output"].getStr(),
|
|
)
|
|
|
|
proc findWorkspacesTree(node: JsonNode, parent: Workspace = Workspace()) =
|
|
for channel in node["nodes"].getElems():
|
|
### move this into for loop if want separate entry per window
|
|
var ws: Workspace = Workspace()
|
|
if parent.num > 0:
|
|
ws = parent
|
|
elif node{"type"}.getStr() == "workspace":
|
|
if node["output"].getStr() == "__i3":
|
|
return
|
|
ws = newWorkspace(node)
|
|
###
|
|
if channel{"window_properties"} != nil:
|
|
let app = getApplication(channel,ws)
|
|
if ws.name != "":
|
|
#if app.focused:
|
|
# ws.focused = true
|
|
ws.applications.add(app)
|
|
ws.application = app
|
|
elif ws.num > 0 and len(channel{"nodes"}) > 0:
|
|
findWorkspacesTree(channel,ws)
|
|
else:
|
|
findWorkspacesTree(channel)
|
|
### move this into for loop if want separate entry per window
|
|
if ws.name != "":
|
|
ws.display_string = ws.buildString()
|
|
if ws.display_string != "":
|
|
my_workspaces.add(ws)
|
|
###
|
|
return
|
|
|
|
proc getTree() =
|
|
let cur_workspaces = execCmdEx(I3_TREE)
|
|
if cur_workspaces.output != "":
|
|
let root = parseJson(cur_workspaces.output)
|
|
findWorkspacesTree(root)
|
|
return
|
|
|
|
proc getWorkspaces(): seq[Workspace] =
|
|
let cur_workspaces = execCmdEx(I3_WORKSPACES)
|
|
if cur_workspaces.output != "":
|
|
let ws = parseJson(cur_workspaces.output)
|
|
for w in ws:
|
|
var space = Workspace(
|
|
num: w["num"].getInt(),
|
|
name: w["name"].getStr(),
|
|
focused: w["focused"].getBool(),
|
|
visible: w["visible"].getBool(),
|
|
urgent: w["urgent"].getBool(),
|
|
output: w["output"].getStr()
|
|
)
|
|
space.display_string = buildString(space)
|
|
my_workspaces.add(space)
|
|
return my_workspaces
|
|
|
|
proc showWorkspaces() =
|
|
my_workspaces = @[]
|
|
getTree()
|
|
var info = newInfo("Workspaces")
|
|
var args: seq[string] = @[]
|
|
for ws in my_workspaces:
|
|
args.add(ws.display_string)
|
|
let output = outputData(info,args)
|
|
if output in args:
|
|
switchWorkspace(output)
|
|
|
|
proc main() =
|
|
showWorkspaces()
|
|
|
|
if isMainModule:
|
|
main()
|