Bar refactor
Nothing visible except more and less bugs, but it's waaaaay easier to work with the code :)
This commit is contained in:
parent
ae0c7c7c09
commit
ca9d5e279e
|
@ -9,10 +9,6 @@ if __name__ == "__main__":
|
|||
Bar.init()
|
||||
Updater.init()
|
||||
|
||||
# Bar.addSectionAll(NotmuchUnreadProvider(dir='~/.mail/', theme=1), BarGroupType.RIGHT)
|
||||
# Bar.addSectionAll(TimeProvider(theme=1), BarGroupType.RIGHT)
|
||||
# else:
|
||||
|
||||
WORKSPACE_THEME = 0
|
||||
FOCUS_THEME = 3
|
||||
URGENT_THEME = 1
|
||||
|
@ -28,10 +24,10 @@ if __name__ == "__main__":
|
|||
SYSTEM_THEME = 2
|
||||
DANGER_THEME = FOCUS_THEME
|
||||
CRITICAL_THEME = URGENT_THEME
|
||||
Bar.addSectionAll(CpuProvider(theme=SYSTEM_THEME, themeDanger=DANGER_THEME, themeCritical=CRITICAL_THEME), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(RamProvider(theme=SYSTEM_THEME, themeDanger=DANGER_THEME, themeCritical=CRITICAL_THEME), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(TemperatureProvider(theme=SYSTEM_THEME, themeDanger=DANGER_THEME, themeCritical=CRITICAL_THEME), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(BatteryProvider(theme=SYSTEM_THEME, themeDanger=DANGER_THEME, themeCritical=CRITICAL_THEME), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(CpuProvider(), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(RamProvider(), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(TemperatureProvider(), BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(BatteryProvider(), BarGroupType.RIGHT)
|
||||
|
||||
# Peripherals
|
||||
PERIPHERAL_THEME = 5
|
||||
|
|
|
@ -17,7 +17,6 @@ log = logging.getLogger()
|
|||
# BarGroup strings should be a good compromise)
|
||||
# TODO Use bytes rather than strings
|
||||
# TODO Use default colors of lemonbar sometimes
|
||||
# TODO Mouse actions
|
||||
# TODO Adapt bar height with font height
|
||||
|
||||
|
||||
|
@ -144,7 +143,6 @@ class Bar:
|
|||
# Color for empty sections
|
||||
Bar.string += BarGroup.color(*Section.EMPTY)
|
||||
|
||||
# print(Bar.string)
|
||||
Bar.process.stdin.write(bytes(Bar.string + '\n', 'utf-8'))
|
||||
Bar.process.stdin.flush()
|
||||
|
||||
|
@ -194,10 +192,6 @@ class BarGroup:
|
|||
def bgColor(color):
|
||||
return "%{B" + (color or '-') + "}"
|
||||
|
||||
@staticmethod
|
||||
def underlineColor(color):
|
||||
return "%{U" + (color or '-') + "}"
|
||||
|
||||
@staticmethod
|
||||
def color(fg, bg):
|
||||
return BarGroup.fgColor(fg) + BarGroup.bgColor(bg)
|
||||
|
@ -291,6 +285,9 @@ class Section:
|
|||
THEMES = list()
|
||||
EMPTY = (FGCOLOR, BGCOLOR)
|
||||
|
||||
ICON = None
|
||||
PERSISTENT = False
|
||||
|
||||
#: Sections that do not have their destination size
|
||||
sizeChanging = set()
|
||||
updateThread = SectionThread(daemon=True)
|
||||
|
@ -321,14 +318,15 @@ class Section:
|
|||
self.curSize = 0
|
||||
|
||||
#: Destination text
|
||||
self.dstText = ''
|
||||
self.dstText = Text(' ', Text(), ' ')
|
||||
#: Destination size
|
||||
self.dstSize = 0
|
||||
|
||||
#: Groups that have this section
|
||||
self.parents = set()
|
||||
|
||||
self.actions = set()
|
||||
self.icon = self.ICON
|
||||
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
|
@ -355,93 +353,25 @@ class Section:
|
|||
for parent in self.parents:
|
||||
parent.childsTextChanged = True
|
||||
|
||||
def parseParts(self, parts, bit='', clo=''):
|
||||
# TODO OPTI Shall benefit of a major refactor, using Objects rather
|
||||
# than dicts and a stack-based approac
|
||||
if isinstance(parts, str):
|
||||
parts = [parts]
|
||||
|
||||
bits = []
|
||||
clos = []
|
||||
for part in parts:
|
||||
if isinstance(part, str):
|
||||
for char in part:
|
||||
bit += char
|
||||
bits.append(bit)
|
||||
clos.append(clo)
|
||||
bit = ''
|
||||
elif isinstance(part, dict):
|
||||
newBit = ''
|
||||
newClo = ''
|
||||
if 'fgColor' in part:
|
||||
newBit = newBit + BarGroup.fgColor(part['fgColor'])
|
||||
newClo = BarGroup.fgColor(Section.THEMES[self.theme][0]) + newClo
|
||||
if 'bgColor' in part:
|
||||
newBit = newBit + BarGroup.bgColor(part['bgColor'])
|
||||
newClo = BarGroup.bgColor(Section.THEMES[self.theme][0]) + newClo
|
||||
if 'underlineColor' in part:
|
||||
newBit = newBit + BarGroup.underlineColor(part['underlineColor'])
|
||||
newClo = BarGroup.underlineColor(None) + newClo
|
||||
if 'underline' in part:
|
||||
newBit = newBit + '%{+u}'
|
||||
newClo = '%{-u}' + newClo
|
||||
if 'overline' in part:
|
||||
newBit = newBit + '%{+o}'
|
||||
newClo = '%{-o}' + newClo
|
||||
if 'mouseLeft' in part:
|
||||
handle = Bar.getFunctionHandle(part['mouseLeft'])
|
||||
newBit = newBit + '%{A1:' + handle.decode() + ':}'
|
||||
newClo = '%{A1}' + newClo
|
||||
if 'mouseMiddle' in part:
|
||||
handle = Bar.getFunctionHandle(part['mouseMiddle'])
|
||||
newBit = newBit + '%{A2:' + handle.decode() + ':}'
|
||||
newClo = '%{A2}' + newClo
|
||||
if 'mouseRight' in part:
|
||||
handle = Bar.getFunctionHandle(part['mouseRight'])
|
||||
newBit = newBit + '%{A3:' + handle.decode() + ':}'
|
||||
newClo = '%{A3}' + newClo
|
||||
if 'mouseScrollUp' in part:
|
||||
handle = Bar.getFunctionHandle(part['mouseScrollUp'])
|
||||
newBit = newBit + '%{A4:' + handle.decode() + ':}'
|
||||
newClo = '%{A4}' + newClo
|
||||
if 'mouseScrollDown' in part:
|
||||
handle = Bar.getFunctionHandle(part['mouseScrollDown'])
|
||||
newBit = newBit + '%{A5:' + handle.decode() + ':}'
|
||||
newClo = '%{A5}' + newClo
|
||||
newBits, newClos = self.parseParts(part["cont"], bit=bit+newBit, clo=newClo+clo)
|
||||
newBits[-1] += newClo # TODO Will sometimes display errors from lemonbar
|
||||
bits += newBits
|
||||
clos += newClos
|
||||
else:
|
||||
raise RuntimeError()
|
||||
|
||||
return bits, clos
|
||||
|
||||
def updateText(self, text):
|
||||
# TODO FEAT Actions
|
||||
# TODO OPTI When srcSize == dstSize, maybe the bit array isn't
|
||||
# needed
|
||||
oldActions = self.actions.copy()
|
||||
assert not isinstance(text, list) # Old behaviour, keep it until everything is cleaned
|
||||
if isinstance(text, str):
|
||||
text = Text(text)
|
||||
|
||||
if len(text):
|
||||
if isinstance(text, str):
|
||||
# TODO OPTI This common case
|
||||
text = [text]
|
||||
if self.icon:
|
||||
self.dstText[0] = ' ' + self.icon + ' '
|
||||
|
||||
self.dstBits, self.dstClos = self.parseParts([' '] + text + [' '])
|
||||
# TODO FEAT Half-spaces
|
||||
|
||||
self.dstText = ''.join(self.dstBits)
|
||||
self.dstSize = len(self.dstBits)
|
||||
if text is None:
|
||||
self.dstSize = 3 if self.PERSISTENT else 0
|
||||
else:
|
||||
self.dstSize = 0
|
||||
|
||||
for action in oldActions:
|
||||
self.unregsiterAction(action)
|
||||
self.dstText[1] = text
|
||||
self.dstText.setSection(self)
|
||||
self.dstSize = len(self.dstText)
|
||||
|
||||
if self.curSize == self.dstSize:
|
||||
self.curText = self.dstText
|
||||
self.informParentsTextChanged()
|
||||
if self.dstSize > 0:
|
||||
self.curText = str(self.dstText)
|
||||
self.informParentsTextChanged()
|
||||
else:
|
||||
Section.sizeChanging.add(self)
|
||||
Section.somethingChanged.set()
|
||||
|
@ -449,6 +379,8 @@ class Section:
|
|||
def updateTheme(self, theme):
|
||||
assert isinstance(theme, int)
|
||||
assert theme < len(Section.THEMES)
|
||||
if theme == self.theme:
|
||||
return
|
||||
self.theme = theme
|
||||
self.informParentsThemeChanged()
|
||||
Section.somethingChanged.set()
|
||||
|
@ -482,9 +414,7 @@ class Section:
|
|||
Section.sizeChanging.remove(self)
|
||||
return
|
||||
|
||||
closPos = self.curSize-1
|
||||
clos = self.dstClos[closPos] if closPos < len(self.dstClos) else ''
|
||||
self.curText = ''.join(Section.fit(self.dstBits, self.curSize)) + clos
|
||||
self.curText = self.dstText.text(size=self.curSize, pad=True)
|
||||
self.informParentsTextChanged()
|
||||
|
||||
@staticmethod
|
||||
|
@ -512,13 +442,15 @@ class Section:
|
|||
|
||||
class StatefulSection(Section):
|
||||
# TODO Allow to temporary expand the section (e.g. when important change)
|
||||
NUMBER_STATES = 4
|
||||
NUMBER_STATES = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Section.__init__(self, *args, **kwargs)
|
||||
self.state = 0
|
||||
if hasattr(self, 'onChangeState'):
|
||||
self.onChangeState(self.state)
|
||||
self.dstText.setDecorators(scrollUp=self.incrementState,
|
||||
scrollDown=self.decrementState)
|
||||
|
||||
def incrementState(self):
|
||||
newState = min(self.state + 1, self.NUMBER_STATES - 1)
|
||||
|
@ -536,18 +468,9 @@ class StatefulSection(Section):
|
|||
self.onChangeState(state)
|
||||
self.refreshData()
|
||||
|
||||
def updateText(self, text):
|
||||
if not len(text):
|
||||
return text
|
||||
Section.updateText(self, [{
|
||||
"mouseScrollUp": self.incrementState,
|
||||
"mouseScrollDown": self.decrementState,
|
||||
"cont": text
|
||||
}])
|
||||
|
||||
class ColorCountsSection(StatefulSection):
|
||||
NUMBER_STATES = 3
|
||||
ICON = '?'
|
||||
COLORABLE_ICON = '?'
|
||||
|
||||
def __init__(self, theme=None):
|
||||
StatefulSection.__init__(self, theme=theme)
|
||||
|
@ -556,59 +479,154 @@ class ColorCountsSection(StatefulSection):
|
|||
counts = self.subfetcher()
|
||||
# Nothing
|
||||
if not len(counts):
|
||||
return ''
|
||||
return None
|
||||
# Icon colored
|
||||
elif self.state == 0 and len(counts) == 1:
|
||||
count, color = counts[0]
|
||||
return [{'fgColor': color, "cont": self.ICON}]
|
||||
return Text(self.COLORABLE_ICON, fg=color)
|
||||
# Icon
|
||||
elif self.state == 0 and len(counts) > 1:
|
||||
return self.ICON
|
||||
return Text(self.COLORABLE_ICON)
|
||||
# Icon + Total
|
||||
elif self.state == 1 and len(counts) > 1:
|
||||
total = sum([count for count, color in counts])
|
||||
return [self.ICON, ' ', str(total)]
|
||||
return Text(self.COLORABLE_ICON, ' ', total)
|
||||
# Icon + Counts
|
||||
else:
|
||||
text = [self.ICON]
|
||||
text = Text(self.COLORABLE_ICON)
|
||||
for count, color in counts:
|
||||
text += [' ', {'fgColor': color, "cont": str(count)}]
|
||||
text.append(' ', Text(count, fg=color))
|
||||
return text
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Bar.init()
|
||||
sec = Section(0)
|
||||
sech = Section(1)
|
||||
sec1 = Section(2)
|
||||
sec2 = Section(3)
|
||||
sec2h = Section(4)
|
||||
sec3 = Section(5)
|
||||
Bar.addSectionAll(sec, BarGroupType.LEFT)
|
||||
Bar.addSectionAll(sech, BarGroupType.LEFT)
|
||||
Bar.addSectionAll(sec1, BarGroupType.LEFT)
|
||||
Bar.addSectionAll(sec2, BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(sec2h, BarGroupType.RIGHT)
|
||||
Bar.addSectionAll(sec3, BarGroupType.RIGHT)
|
||||
class Text:
|
||||
def _setElements(self, elements):
|
||||
# TODO OPTI Concatenate consecutrive string
|
||||
self.elements = list(elements)
|
||||
|
||||
time.sleep(1)
|
||||
sec.updateText("A")
|
||||
time.sleep(1)
|
||||
sec.updateText("")
|
||||
time.sleep(1)
|
||||
sec.updateText("Hello")
|
||||
sec1.updateText("world!")
|
||||
sec2.updateText("Salut")
|
||||
sec2h.updateText("le")
|
||||
sec3.updateText("monde !")
|
||||
time.sleep(3)
|
||||
sech.updateText("the")
|
||||
sec2h.updateText("")
|
||||
time.sleep(2)
|
||||
sec.updateText("")
|
||||
sech.updateText("")
|
||||
sec1.updateText("")
|
||||
sec2.updateText("")
|
||||
sec2h.updateText("")
|
||||
sec3.updateText("")
|
||||
time.sleep(5)
|
||||
def _setDecorators(self, decorators):
|
||||
# TODO OPTI Convert no decorator to strings
|
||||
self.decorators = decorators
|
||||
self.prefix = None
|
||||
self.suffix = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._setElements(args)
|
||||
self._setDecorators(kwargs)
|
||||
self.section = None
|
||||
|
||||
def append(self, *args):
|
||||
self._setElements(self.elements + list(args))
|
||||
|
||||
def prepend(self, *args):
|
||||
self._setElements(list(args) + self.elements)
|
||||
|
||||
def setElements(self, *args):
|
||||
self._setElements(args)
|
||||
|
||||
def setDecorators(self, **kwargs):
|
||||
self._setDecorators(kwargs)
|
||||
|
||||
def setSection(self, section):
|
||||
assert isinstance(section, Section)
|
||||
self.section = section
|
||||
for element in self.elements:
|
||||
if isinstance(element, Text):
|
||||
element.setSection(section)
|
||||
|
||||
def _genFixs(self):
|
||||
if self.prefix is not None and self.suffix is not None:
|
||||
return
|
||||
|
||||
self.prefix = ''
|
||||
self.suffix = ''
|
||||
|
||||
def nest(prefix, suffix):
|
||||
self.prefix = self.prefix + '%{' + prefix + '}'
|
||||
self.suffix = '%{' + suffix + '}' + self.suffix
|
||||
|
||||
def getColor(val):
|
||||
# TODO Allow themes
|
||||
assert isinstance(val, str) and len(val) == 7
|
||||
return val
|
||||
|
||||
def button(number, function):
|
||||
handle = Bar.getFunctionHandle(function)
|
||||
nest('A' + number + ':' + handle.decode() + ':', 'A' + number)
|
||||
|
||||
for key, val in self.decorators.items():
|
||||
if key == 'fg':
|
||||
reset = self.section.THEMES[self.section.theme][0]
|
||||
nest('F' + getColor(val), 'F' + reset)
|
||||
elif key == 'bg':
|
||||
reset = self.section.THEMES[self.section.theme][1]
|
||||
nest('B' + getColor(val), 'B' + reset)
|
||||
elif key == "clickLeft":
|
||||
button('1', val)
|
||||
elif key == "clickMiddle":
|
||||
button('2', val)
|
||||
elif key == "clickRight":
|
||||
button('3', val)
|
||||
elif key == "scrollUp":
|
||||
button('4', val)
|
||||
elif key == "scrollDown":
|
||||
button('5', val)
|
||||
else:
|
||||
log.warn("Unkown decorator: {}".format(key))
|
||||
|
||||
def _text(self, size=None, pad=False):
|
||||
self._genFixs()
|
||||
curString = self.prefix
|
||||
curSize = 0
|
||||
remSize = size
|
||||
|
||||
for element in self.elements:
|
||||
if element is None:
|
||||
continue
|
||||
elif isinstance(element, Text):
|
||||
newString, newSize = element._text(size=remSize)
|
||||
else:
|
||||
newString = str(element)
|
||||
if remSize is not None:
|
||||
newString = newString[:remSize]
|
||||
newSize = len(newString)
|
||||
|
||||
curString += newString
|
||||
curSize += newSize
|
||||
|
||||
if remSize is not None:
|
||||
remSize -= newSize
|
||||
if remSize <= 0:
|
||||
break
|
||||
|
||||
curString += self.suffix
|
||||
|
||||
if pad and remSize > 0:
|
||||
curString += ' ' * remSize
|
||||
curSize += remSize
|
||||
|
||||
if size is not None:
|
||||
if pad:
|
||||
assert size == curSize
|
||||
else:
|
||||
assert size >= curSize
|
||||
return curString, curSize
|
||||
|
||||
def text(self, *args, **kwargs):
|
||||
string, size = self._text(*args, **kwargs)
|
||||
return string
|
||||
|
||||
def __str__(self):
|
||||
# TODO OPTI
|
||||
return self.text()
|
||||
|
||||
def __len__(self):
|
||||
# TODO OPTI
|
||||
string, size = self._text()
|
||||
return size
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.elements[index]
|
||||
|
||||
def __setitem__(self, index, data):
|
||||
self.elements[index] = data
|
||||
|
|
|
@ -53,25 +53,60 @@ class TimeProvider(StatefulSection, PeriodicUpdater):
|
|||
StatefulSection.__init__(self, theme)
|
||||
self.changeInterval(1) # TODO OPTI When state < 1
|
||||
|
||||
class CpuProvider(Section, PeriodicUpdater):
|
||||
class AlertLevel(enum.Enum):
|
||||
NORMAL = 0
|
||||
WARNING = 1
|
||||
DANGER = 2
|
||||
|
||||
class AlertingSection(StatefulSection):
|
||||
# TODO EASE Correct settings for themes
|
||||
THEMES = {AlertLevel.NORMAL: 2,
|
||||
AlertLevel.WARNING: 3,
|
||||
AlertLevel.DANGER: 1}
|
||||
PERSISTENT = True
|
||||
|
||||
def getLevel(self, quantity):
|
||||
if quantity > self.dangerThresold:
|
||||
return AlertLevel.DANGER
|
||||
elif quantity > self.warningThresold:
|
||||
return AlertLevel.WARNING
|
||||
else:
|
||||
return AlertLevel.NORMAL
|
||||
|
||||
def updateLevel(self, quantity):
|
||||
self.level = self.getLevel(quantity)
|
||||
self.updateTheme(self.THEMES[self.level])
|
||||
if self.level == AlertLevel.NORMAL:
|
||||
return
|
||||
# TODO Temporary update state
|
||||
|
||||
def __init__(self, theme):
|
||||
StatefulSection.__init__(self, theme)
|
||||
self.dangerThresold = 0.90
|
||||
self.warningThresold = 0.75
|
||||
|
||||
|
||||
class CpuProvider(AlertingSection, PeriodicUpdater):
|
||||
NUMBER_STATES = 3
|
||||
ICON = ''
|
||||
|
||||
def fetcher(self):
|
||||
percents = psutil.cpu_percent(percpu=True)
|
||||
percent = psutil.cpu_percent(percpu=False)
|
||||
theme = self.themeCritical if percent >= 90 else \
|
||||
(self.themeDanger if percent >= 75 else self.themeNormal)
|
||||
self.updateTheme(theme)
|
||||
return ' ' + ''.join([Section.ramp(p/100) for p in percents])
|
||||
self.updateLevel(percent/100)
|
||||
if self.state >= 2:
|
||||
percents = psutil.cpu_percent(percpu=True)
|
||||
return ''.join([Section.ramp(p/100) for p in percents])
|
||||
elif self.state >= 1:
|
||||
return Section.ramp(percent/100)
|
||||
|
||||
def __init__(self, theme=None, themeDanger=None, themeCritical=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
PeriodicUpdater.__init__(self)
|
||||
Section.__init__(self, theme)
|
||||
self.themeNormal = theme or self.theme
|
||||
self.themeDanger = themeDanger or self.theme
|
||||
self.themeCritical = themeCritical or self.theme
|
||||
self.changeInterval(1)
|
||||
|
||||
|
||||
class RamProvider(Section, PeriodicUpdater):
|
||||
# TODO Use AlertingSection
|
||||
"""
|
||||
Shows free RAM
|
||||
"""
|
||||
|
@ -93,7 +128,7 @@ class RamProvider(Section, PeriodicUpdater):
|
|||
self.changeInterval(1)
|
||||
|
||||
class TemperatureProvider(Section, PeriodicUpdater):
|
||||
# TODO FEAT Change color when > high > critical
|
||||
# TODO Use AlertingSection
|
||||
|
||||
RAMP = ""
|
||||
|
||||
|
@ -124,7 +159,7 @@ class TemperatureProvider(Section, PeriodicUpdater):
|
|||
|
||||
|
||||
class BatteryProvider(Section, PeriodicUpdater):
|
||||
# TODO Change color when < thresold%
|
||||
# TODO Use AlertingSection
|
||||
|
||||
RAMP = ""
|
||||
|
||||
|
@ -194,24 +229,23 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
|
||||
NUMBER_STATES = 4
|
||||
|
||||
def getIcon(self):
|
||||
def actType(self):
|
||||
self.ssid = None
|
||||
if self.iface.startswith('eth') or self.iface.startswith('enp'):
|
||||
if 'u' in self.iface:
|
||||
return ['']
|
||||
self.icon = ''
|
||||
else:
|
||||
return ['']
|
||||
self.icon = ''
|
||||
elif self.iface.startswith('wlan') or self.iface.startswith('wlp'):
|
||||
if self.state > 0:
|
||||
self.icon = ''
|
||||
if self.showSsid:
|
||||
cmd = ["iwgetid", self.iface, "--raw"]
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE)
|
||||
ssid = p.stdout.strip().decode()
|
||||
return [' {}'.format(ssid)]
|
||||
else:
|
||||
return ['']
|
||||
self.ssid = p.stdout.strip().decode()
|
||||
elif self.iface.startswith('tun') or self.iface.startswith('tap'):
|
||||
return ['']
|
||||
self.icon = ''
|
||||
else:
|
||||
return ['?']
|
||||
self.icon = '?'
|
||||
|
||||
def getAddresses(self):
|
||||
ipv4 = None
|
||||
|
@ -224,26 +258,28 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
return ipv4, ipv6
|
||||
|
||||
def fetcher(self):
|
||||
text = []
|
||||
|
||||
if self.iface not in self.parent.stats or \
|
||||
not self.parent.stats[self.iface].isup or \
|
||||
self.iface.startswith('lo'):
|
||||
return text
|
||||
return None
|
||||
|
||||
# Get addresses
|
||||
ipv4, ipv6 = self.getAddresses()
|
||||
if ipv4 is None and ipv6 is None:
|
||||
return text
|
||||
return None
|
||||
|
||||
text = self.getIcon()
|
||||
text = []
|
||||
self.actType()
|
||||
|
||||
if self.showSsid and self.ssid:
|
||||
text.append(self.ssid)
|
||||
|
||||
if self.showAddress:
|
||||
if ipv4:
|
||||
netStrFull = '{}/{}'.format(ipv4.address, ipv4.netmask)
|
||||
addr = ipaddress.IPv4Network(netStrFull, strict=False)
|
||||
addrStr = ' {}/{}'.format(ipv4.address, addr.prefixlen)
|
||||
text += [addrStr]
|
||||
addrStr = '{}/{}'.format(ipv4.address, addr.prefixlen)
|
||||
text.append(addrStr)
|
||||
# TODO IPV6
|
||||
# if ipv6:
|
||||
# text += ' ' + ipv6.address
|
||||
|
@ -255,16 +291,18 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
- self.parent.prevIO[self.iface].bytes_sent
|
||||
recvDiff /= self.parent.dt
|
||||
sentDiff /= self.parent.dt
|
||||
text += [' ↓{}↑{}'.format(humanSize(recvDiff), humanSize(sentDiff))]
|
||||
text.append('↓{}↑{}'.format(humanSize(recvDiff),
|
||||
humanSize(sentDiff)))
|
||||
|
||||
if self.showTransfer:
|
||||
text += [' ⇓{}⇑{}'.format(
|
||||
text.append('⇓{}⇑{}'.format(
|
||||
humanSize(self.parent.IO[self.iface].bytes_recv),
|
||||
humanSize(self.parent.IO[self.iface].bytes_sent))]
|
||||
humanSize(self.parent.IO[self.iface].bytes_sent)))
|
||||
|
||||
return text
|
||||
return ' '.join(text)
|
||||
|
||||
def onChangeState(self, state):
|
||||
self.showSsid = state >= 0
|
||||
self.showAddress = state >= 1
|
||||
self.showSpeed = state >= 2
|
||||
self.showTransfer = state >= 3
|
||||
|
@ -307,7 +345,7 @@ class NetworkProvider(Section, PeriodicUpdater):
|
|||
for section in self.sections.values():
|
||||
section.refreshData()
|
||||
|
||||
return ''
|
||||
return None
|
||||
|
||||
def addParent(self, parent):
|
||||
self.parents.add(parent)
|
||||
|
@ -328,15 +366,13 @@ class SshAgentProvider(PeriodicUpdater):
|
|||
cmd = ["ssh-add", "-l"]
|
||||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
if proc.returncode != 0:
|
||||
return ''
|
||||
text = []
|
||||
return None
|
||||
text = Text()
|
||||
for line in proc.stdout.split(b'\n'):
|
||||
if not len(line):
|
||||
continue
|
||||
fingerprint = line.split()[1]
|
||||
text += [{"cont": '',
|
||||
"fgColor": randomColor(seed=fingerprint)
|
||||
}]
|
||||
text.append(Text('', fg=randomColor(seed=fingerprint)))
|
||||
return text
|
||||
|
||||
def __init__(self):
|
||||
|
@ -349,8 +385,8 @@ class GpgAgentProvider(PeriodicUpdater):
|
|||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
# proc = subprocess.run(cmd)
|
||||
if proc.returncode != 0:
|
||||
return ''
|
||||
text = []
|
||||
return None
|
||||
text = Text()
|
||||
for line in proc.stdout.split(b'\n'):
|
||||
if not len(line) or line == b'OK':
|
||||
continue
|
||||
|
@ -358,9 +394,7 @@ class GpgAgentProvider(PeriodicUpdater):
|
|||
if spli[6] != b'1':
|
||||
continue
|
||||
keygrip = spli[2]
|
||||
text += [{"cont": '',
|
||||
"fgColor": randomColor(seed=keygrip)
|
||||
}]
|
||||
text.append(Text('', fg=randomColor(seed=keygrip)))
|
||||
return text
|
||||
|
||||
def __init__(self):
|
||||
|
@ -368,14 +402,16 @@ class GpgAgentProvider(PeriodicUpdater):
|
|||
self.changeInterval(5)
|
||||
|
||||
class KeystoreProvider(Section, MergedUpdater):
|
||||
ICON = ''
|
||||
|
||||
def __init__(self, theme=None):
|
||||
MergedUpdater.__init__(self, SshAgentProvider(), GpgAgentProvider(), prefix=[' '])
|
||||
MergedUpdater.__init__(self, SshAgentProvider(), GpgAgentProvider())
|
||||
Section.__init__(self, theme)
|
||||
|
||||
class NotmuchUnreadProvider(ColorCountsSection, PeriodicUpdater):
|
||||
# TODO OPTI Transform InotifyUpdater (watching notmuch folder should be
|
||||
# enough)
|
||||
ICON = ''
|
||||
COLORABLE_ICON = ''
|
||||
|
||||
def subfetcher(self):
|
||||
db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY, path=self.dir)
|
||||
|
@ -414,7 +450,7 @@ class NotmuchUnreadProvider(ColorCountsSection, PeriodicUpdater):
|
|||
class TodoProvider(ColorCountsSection, InotifyUpdater):
|
||||
# TODO OPT/UX Maybe we could get more data from the todoman python module
|
||||
# TODO OPT Specific callback for specific directory
|
||||
ICON = ''
|
||||
COLORABLE_ICON = ''
|
||||
|
||||
def updateCalendarList(self):
|
||||
calendars = sorted(os.listdir(self.dir))
|
||||
|
@ -575,6 +611,7 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
self.initialPopulation(parent)
|
||||
|
||||
class MpdProvider(Section, ThreadedUpdater):
|
||||
# TODO FEAT More informations and controls
|
||||
|
||||
MAX_LENGTH = 50
|
||||
|
||||
|
@ -610,9 +647,7 @@ class MpdProvider(Section, ThreadedUpdater):
|
|||
if len(infosStr) > MpdProvider.MAX_LENGTH:
|
||||
infosStr = infosStr[:MpdProvider.MAX_LENGTH-1] + '…'
|
||||
|
||||
text = [" {}".format(infosStr)]
|
||||
|
||||
return text
|
||||
return " {}".format(infosStr)
|
||||
|
||||
def loop(self):
|
||||
try:
|
||||
|
@ -624,3 +659,4 @@ class MpdProvider(Section, ThreadedUpdater):
|
|||
except BaseException as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import time
|
|||
import logging
|
||||
import coloredlogs
|
||||
import i3ipc
|
||||
from display import Text
|
||||
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
log = logging.getLogger()
|
||||
|
@ -231,23 +232,17 @@ class MergedUpdater(Updater):
|
|||
|
||||
# TODO OPTI Do not update until end of periodic batch
|
||||
def fetcher(self):
|
||||
text = []
|
||||
text = Text()
|
||||
for updater in self.updaters:
|
||||
data = self.texts[updater]
|
||||
if not len(data):
|
||||
continue
|
||||
if isinstance(data, str):
|
||||
data = [data]
|
||||
text += data
|
||||
if not len(text):
|
||||
return ''
|
||||
return self.prefix + text + self.suffix
|
||||
text.append(self.texts[updater])
|
||||
# TODO OPTI After Text.__len__
|
||||
# if not len(text):
|
||||
# return None
|
||||
return text
|
||||
|
||||
def __init__(self, *args, prefix=[''], suffix=['']):
|
||||
def __init__(self, *args):
|
||||
Updater.__init__(self)
|
||||
|
||||
self.prefix = prefix
|
||||
self.suffix = suffix
|
||||
self.updaters = []
|
||||
self.texts = dict()
|
||||
|
||||
|
|
Loading…
Reference in a new issue