dotfiles/config/nix/hm/frobar/.dev/pip.py

328 lines
7.6 KiB
Python
Raw Normal View History

2018-08-21 18:10:57 +02:00
#!/usr/bin/env python3
"""
Beautiful script
"""
import subprocess
import time
import datetime
import os
import multiprocessing
import i3ipc
import difflib
# Constants
2021-07-04 09:52:16 +02:00
FONT = "DejaVuSansMono Nerd Font Mono"
2018-08-21 18:10:57 +02:00
2018-08-21 21:50:44 +02:00
# TODO Update to be in sync with base16
2021-06-13 11:49:21 +02:00
thm = [
"#002b36",
"#dc322f",
"#859900",
"#b58900",
"#268bd2",
"#6c71c4",
"#2aa198",
"#93a1a1",
"#657b83",
"#dc322f",
"#859900",
"#b58900",
"#268bd2",
"#6c71c4",
"#2aa198",
"#fdf6e3",
]
fg = "#93a1a1"
bg = "#002b36"
2018-08-21 18:10:57 +02:00
THEMES = {
2021-06-13 11:49:21 +02:00
"CENTER": (fg, bg),
"DEFAULT": (thm[0], thm[8]),
"1": (thm[0], thm[9]),
"2": (thm[0], thm[10]),
"3": (thm[0], thm[11]),
"4": (thm[0], thm[12]),
"5": (thm[0], thm[13]),
"6": (thm[0], thm[14]),
"7": (thm[0], thm[15]),
2018-08-21 21:50:44 +02:00
}
2018-08-21 18:10:57 +02:00
# Utils
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def fitText(text, size):
"""
Add spaces or cut a string to be `size` characters long
"""
if size > 0:
2018-08-21 21:50:44 +02:00
t = len(text)
if t >= size:
2018-08-21 18:10:57 +02:00
return text[:size]
else:
2018-08-21 21:50:44 +02:00
diff = size - t
return text + " " * diff
2018-08-21 18:10:57 +02:00
else:
2021-06-13 11:49:21 +02:00
return ""
2018-08-21 18:10:57 +02:00
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def fgColor(theme):
global THEMES
return THEMES[theme][0]
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def bgColor(theme):
global THEMES
return THEMES[theme][1]
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
class Section:
2021-06-13 11:49:21 +02:00
def __init__(self, theme="DEFAULT"):
self.text = ""
2018-08-21 18:10:57 +02:00
self.size = 0
self.toSize = 0
self.theme = theme
self.visible = False
2021-06-13 11:49:21 +02:00
self.name = ""
2018-08-21 18:10:57 +02:00
def update(self, text):
2021-06-13 11:49:21 +02:00
if text == "":
2018-08-21 18:10:57 +02:00
self.toSize = 0
else:
if len(text) < len(self.text):
2021-06-13 11:49:21 +02:00
self.text = text + self.text[len(text) :]
2018-08-21 18:10:57 +02:00
else:
self.text = text
self.toSize = len(text) + 3
def updateSize(self):
"""
Set the size for the next frame of animation
Return if another frame is needed
"""
if self.toSize > self.size:
self.size += 1
elif self.toSize < self.size:
self.size -= 1
self.visible = self.size
return self.toSize == self.size
2021-06-13 11:49:21 +02:00
def draw(self, left=True, nextTheme="DEFAULT"):
s = ""
2018-08-21 18:10:57 +02:00
if self.visible:
if not left:
if self.theme == nextTheme:
2021-06-13 11:49:21 +02:00
s += ""
2018-08-21 18:10:57 +02:00
else:
2021-06-13 11:49:21 +02:00
s += "%{F" + bgColor(self.theme) + "}"
s += "%{B" + bgColor(nextTheme) + "}"
s += ""
s += "%{F" + fgColor(self.theme) + "}"
s += "%{B" + bgColor(self.theme) + "}"
s += " " if self.size > 1 else ""
2018-08-21 18:10:57 +02:00
s += fitText(self.text, self.size - 3)
2021-06-13 11:49:21 +02:00
s += " " if self.size > 2 else ""
2018-08-21 18:10:57 +02:00
if left:
if self.theme == nextTheme:
2021-06-13 11:49:21 +02:00
s += ""
2018-08-21 18:10:57 +02:00
else:
2021-06-13 11:49:21 +02:00
s += "%{F" + bgColor(self.theme) + "}"
s += "%{B" + bgColor(nextTheme) + "}"
s += ""
2018-08-21 18:10:57 +02:00
return s
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
# Section definition
2021-06-13 11:49:21 +02:00
sTime = Section("3")
2018-08-21 18:10:57 +02:00
2021-06-13 11:49:21 +02:00
hostname = os.environ["HOSTNAME"].split(".")[0]
sHost = Section("2")
2018-08-21 21:50:44 +02:00
sHost.update(
2021-06-13 11:49:21 +02:00
os.environ["USER"] + "@" + hostname.split("-")[-1] if "-" in hostname else hostname
)
2018-08-21 18:10:57 +02:00
# Groups definition
gLeft = []
gRight = [sTime, sHost]
# Bar handling
2021-06-13 11:49:21 +02:00
bar = subprocess.Popen(["lemonbar", "-f", FONT, "-b"], stdin=subprocess.PIPE)
2018-08-21 18:10:57 +02:00
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def updateBar():
global timeLastUpdate, timeUpdate
global gLeft, gRight
global outputs
2021-06-13 11:49:21 +02:00
text = ""
2018-08-21 18:10:57 +02:00
for oi in range(len(outputs)):
output = outputs[oi]
2018-08-21 21:50:44 +02:00
gLeftFiltered = list(
filter(
2021-06-13 11:49:21 +02:00
lambda s: s.visible and (not s.output or s.output == output.name), gLeft
)
)
tLeft = ""
2018-08-21 18:10:57 +02:00
l = len(gLeftFiltered)
for gi in range(l):
g = gLeftFiltered[gi]
2018-08-21 21:50:44 +02:00
# Next visible section for transition
2021-06-13 11:49:21 +02:00
nextTheme = gLeftFiltered[gi + 1].theme if gi + 1 < l else "CENTER"
2018-08-21 18:10:57 +02:00
tLeft = tLeft + g.draw(True, nextTheme)
2021-06-13 11:49:21 +02:00
tRight = ""
2018-08-21 18:10:57 +02:00
for gi in range(len(gRight)):
g = gRight[gi]
2021-06-13 11:49:21 +02:00
nextTheme = "CENTER"
for gn in gRight[gi + 1 :]:
2018-08-21 18:10:57 +02:00
if gn.visible:
nextTheme = gn.theme
break
tRight = g.draw(False, nextTheme) + tRight
2021-06-13 11:49:21 +02:00
text += (
"%{l}"
+ tLeft
+ "%{r}"
+ tRight
+ "%{B"
+ bgColor("CENTER")
+ "}"
+ "%{S"
+ str(oi + 1)
+ "}"
)
bar.stdin.write(bytes(text + "\n", "utf-8"))
2018-08-21 18:10:57 +02:00
bar.stdin.flush()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
# Values
i3 = i3ipc.Connection()
outputs = []
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def on_output():
global outputs
2018-08-21 21:50:44 +02:00
outputs = sorted(
sorted(
2021-06-13 11:49:21 +02:00
list(filter(lambda o: o.active, i3.get_outputs())), key=lambda o: o.rect.y
),
key=lambda o: o.rect.x,
)
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
on_output()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def on_workspace_focus():
global i3
global gLeft
workspaces = i3.get_workspaces()
wNames = [w.name for w in workspaces]
sNames = [s.name for s in gLeft]
newGLeft = []
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def actuate(section, workspace):
if workspace:
section.name = workspace.name
section.output = workspace.output
if workspace.visible:
section.update(workspace.name)
else:
2021-06-13 11:49:21 +02:00
section.update(workspace.name.split(" ")[0])
2018-08-21 18:10:57 +02:00
if workspace.focused:
2021-06-13 11:49:21 +02:00
section.theme = "4"
2018-08-21 18:10:57 +02:00
elif workspace.urgent:
2021-06-13 11:49:21 +02:00
section.theme = "1"
2018-08-21 18:10:57 +02:00
else:
2021-06-13 11:49:21 +02:00
section.theme = "6"
2018-08-21 18:10:57 +02:00
else:
2021-06-13 11:49:21 +02:00
section.update("")
section.theme = "6"
2018-08-21 18:10:57 +02:00
2021-06-13 11:49:21 +02:00
for tag, i, j, k, l in difflib.SequenceMatcher(None, sNames, wNames).get_opcodes():
if tag == "equal": # If the workspaces didn't changed
2018-08-21 21:50:44 +02:00
for a in range(j - i):
workspace = workspaces[k + a]
section = gLeft[i + a]
2018-08-21 18:10:57 +02:00
actuate(section, workspace)
newGLeft.append(section)
2021-06-13 11:49:21 +02:00
if tag in ("delete", "replace"): # If the workspaces were removed
2018-08-21 18:10:57 +02:00
for section in gLeft[i:j]:
if section.visible:
actuate(section, None)
newGLeft.append(section)
else:
del section
2021-06-13 11:49:21 +02:00
if tag in ("insert", "replace"): # If the workspaces were removed
2018-08-21 18:10:57 +02:00
for workspace in workspaces[k:l]:
section = Section()
actuate(section, workspace)
newGLeft.append(section)
gLeft = newGLeft
updateBar()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
on_workspace_focus()
def i3events(i3childPipe):
global i3
# Proxy functions
def on_workspace_focus(i3, e):
global i3childPipe
2021-06-13 11:49:21 +02:00
i3childPipe.send("on_workspace_focus")
2018-08-21 18:10:57 +02:00
i3.on("workspace::focus", on_workspace_focus)
def on_output(i3, e):
global i3childPipe
2021-06-13 11:49:21 +02:00
i3childPipe.send("on_output")
2018-08-21 18:10:57 +02:00
i3.on("output", on_output)
i3.main()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
i3parentPipe, i3childPipe = multiprocessing.Pipe()
i3process = multiprocessing.Process(target=i3events, args=(i3childPipe,))
i3process.start()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def updateValues():
# Time
now = datetime.datetime.now()
2021-06-13 11:49:21 +02:00
sTime.update(now.strftime("%x %X"))
2018-08-21 18:10:57 +02:00
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
def updateAnimation():
for s in set(gLeft + gRight):
s.updateSize()
updateBar()
2018-08-21 21:50:44 +02:00
2018-08-21 18:10:57 +02:00
lastUpdate = 0
while True:
now = time.time()
if i3parentPipe.poll():
msg = i3parentPipe.recv()
2021-06-13 11:49:21 +02:00
if msg == "on_workspace_focus":
2018-08-21 18:10:57 +02:00
on_workspace_focus()
2021-06-13 11:49:21 +02:00
elif msg == "on_output":
2018-08-21 18:10:57 +02:00
on_output()
# TODO Restart lemonbar
else:
print(msg)
updateAnimation()
if now >= lastUpdate + 1:
updateValues()
lastUpdate = now
time.sleep(0.05)