Added data collection for details box

pull/27/head
aristocratos 4 years ago
parent 3a07ef4bfd
commit 88abc5ab1a

@ -23,12 +23,13 @@ from datetime import timedelta
from _thread import interrupt_main
from collections import defaultdict
from select import select
from itertools import cycle
from distutils.util import strtobool
from string import Template
from math import ceil, floor
from random import randint
from shutil import which
from typing import List, Set, Dict, Tuple, Optional, Union, Any, Callable, ContextManager, Iterable, Type
from typing import List, Set, Dict, Tuple, Optional, Union, Any, Callable, ContextManager, Iterable, Type, NamedTuple
errors: List[str] = []
try: import fcntl, termios, tty
@ -1610,15 +1611,15 @@ class MemBox(Box):
Draw.buffer("mem_misc", out_misc, only_save=True)
#* Mem
out += f'{Mv.to(y, x+1)}{THEME.title}{Fx.b}Total:{mem.string["total"]:>{cls.mem_width - 9}}{Fx.ub}{THEME.main_fg}'
cx = 1; cy = 1
out += f'{Mv.to(y, x+1)}{THEME.title}{Fx.b}Total:{mem.string["total"]:>{cls.mem_width - 9}}{Fx.ub}{THEME.main_fg}'
if cls.graph_height > 0:
gli = f'{Mv.l(2)}{THEME.mem_box(Symbol.title_right)}{THEME.div_line}{Symbol.h_line * (cls.mem_width - 1)}{"" if CONFIG.show_disks else THEME.mem_box}{Symbol.title_left}{Mv.l(cls.mem_width - 1)}{THEME.title}'
if cls.graph_height >= 2:
gbg = f'{Mv.l(1)}'
gmv = f'{Mv.l(cls.mem_width - 2)}{Mv.u(cls.graph_height - 1)}'
big_mem: bool = True if cls.mem_width > 21 else False
for name in cls.mem_names:
if cls.mem_size > 2:
@ -1633,6 +1634,7 @@ class MemBox(Box):
if h - cy > 5:
if cls.graph_height > 0: out += f'{Mv.to(y+cy, x+cx)}{gli}'
cy += 1
out += f'{Mv.to(y+cy, x+cx)}{THEME.title}{Fx.b}Swap:{mem.swap_string["total"]:>{cls.mem_width - 8}}{Fx.ub}{THEME.main_fg}'
cy += 1
for name in cls.swap_names:
@ -1754,9 +1756,11 @@ class ProcBox(Box):
width_p = 55
x = 1
y = 1
current_y: int = 0
select_max: int = 0
selected: int = 0
selected_pid: int
selected_pid: int = 0
filtering: bool = False
moved: bool = False
start: int = 1
count: int = 0
@ -1781,7 +1785,6 @@ class ProcBox(Box):
cls.detailed_y = cls.y
cls.detailed_height = 8
cls.detailed_width = cls.width
cls.select_max = cls.height - 3
cls.redraw = True
cls.resized = True
@ -1790,7 +1793,7 @@ class ProcBox(Box):
return create_box(box=cls, line_color=THEME.proc_box)
@classmethod
def selector(cls, key: str) -> bool:
def selector(cls, key: str, mouse_pos: Tuple[int, int] = (0, 0)):
old: Tuple[int, int] = (cls.start, cls.selected)
if key == "up":
if cls.selected == 1 and cls.start > 1:
@ -1818,18 +1821,35 @@ class ProcBox(Box):
elif key == "end":
if cls.start < ProcCollector.num_procs - cls.select_max + 1: cls.start = ProcCollector.num_procs - cls.select_max + 1
elif cls.selected < cls.select_max: cls.selected = cls.select_max
elif key == "mouse_click":
if mouse_pos[0] > cls.x + cls.width - 4 and mouse_pos[1] > cls.current_y and mouse_pos[1] < cls.current_y + cls.select_max:
if mouse_pos[1] == cls.current_y + 1:
cls.start = 1
elif mouse_pos[1] == cls.current_y + cls.select_max - 1:
cls.start = ProcCollector.num_procs - cls.select_max + 1
else:
cls.start = round((mouse_pos[1] - cls.current_y - 1) * ((ProcCollector.num_procs - cls.select_max - 2) / (cls.select_max - 2)))
else:
cls.selected = mouse_pos[1] - cls.current_y if mouse_pos[1] >= cls.current_y else cls.selected
elif key == "mouse_unselect":
cls.selected = 0
if cls.start > ProcCollector.num_procs - cls.select_max + 1 and ProcCollector.num_procs > cls.select_max: cls.start = ProcCollector.num_procs - cls.select_max + 1
elif cls.start > ProcCollector.num_procs: cls.start = ProcCollector.num_procs
if cls.start < 1: cls.start = 1
if cls.start > ProcCollector.num_procs - cls.select_max + 1: cls.start = ProcCollector.num_procs - cls.select_max + 1
if cls.selected > ProcCollector.num_procs and ProcCollector.num_procs < cls.select_max: cls.selected = ProcCollector.num_procs
elif cls.selected > cls.select_max: cls.selected = cls.select_max
if cls.selected < 0: cls.selected = 0
if old != (cls.start, cls.selected):
cls.moved = True
return True
else:
return False
Collector.collect(ProcCollector, proc_interrupt=True, only_draw=True)
@classmethod
def _draw_fg(cls):
proc = ProcCollector
if proc.proc_interrupt: return
if proc.redraw: cls.redraw = True
out: str = ""
out_misc: str = ""
@ -1838,47 +1858,65 @@ class ProcBox(Box):
prog_len: int; arg_len: int; val: int; c_color: str; m_color: str; t_color: str; sort_pos: int; tree_len: int; is_selected: bool; calc: int
l_count: int = 0
loc_string: str
scroll_pos: int = 0
indent: str = ""
offset: int = 0
vals: List[str]
c_color = m_color = t_color = Fx.b
g_color: str = ""
s_len: int = 0
if proc.search_filter: s_len = len(proc.search_filter[:10])
end: str = ""
if w > 67: arg_len = w - 53; prog_len = 15
else: arg_len = 0; prog_len = w - 38
if w > 67:
arg_len = w - 53 - (1 if proc.num_procs > cls.select_max else 0)
prog_len = 15
else:
arg_len = 0
prog_len = w - 38 - (1 if proc.num_procs > cls.select_max else 0)
if CONFIG.proc_tree:
tree_len = arg_len + prog_len + 6
arg_len = 0
if cls.resized or cls.redraw:
cls.select_max = h - 1
cls.current_y = y
sort_pos = x + w - len(CONFIG.proc_sorting) - 7
Key.mouse["left"] = [[sort_pos + i, y-1] for i in range(3)]
Key.mouse["right"] = [[sort_pos + len(CONFIG.proc_sorting) + 3 + i, y-1] for i in range(3)]
Key.mouse["e"] = [[sort_pos - 5 + i, y-1] for i in range(4)]
out_misc += (f'{Mv.to(y-1, x + 15)}{THEME.proc_box(Symbol.h_line * (w - 16))}'
out_misc += (f'{Mv.to(y-1, x + 8)}{THEME.proc_box(Symbol.h_line * (w - 9))}'
f'{Mv.to(y-1, sort_pos)}{THEME.proc_box(Symbol.title_left)}{Fx.b}{THEME.hi_fg("<")} {THEME.title(CONFIG.proc_sorting)} '
f'{THEME.hi_fg(">")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}'
f'{Mv.to(y-1, sort_pos - 6)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_tree else ""}'
f'{THEME.title("tre")}{THEME.hi_fg("e")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 50:
f'{THEME.hi_fg(">")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 37 + s_len:
out_misc += (f'{Mv.to(y-1, sort_pos - 6)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_tree else ""}'
f'{THEME.title("tre")}{THEME.hi_fg("e")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 45 + s_len:
Key.mouse["r"] = [[sort_pos - 14 + i, y-1] for i in range(7)]
out_misc += (f'{Mv.to(y-1, sort_pos - 15)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_reversed else ""}'
f'{THEME.hi_fg("r")}{THEME.title("everse")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 58:
Key.mouse["c"] = [[sort_pos - 22 + i, y-1] for i in range(6)]
out_misc += (f'{Mv.to(y-1, sort_pos - 23)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_colors else ""}'
f'{THEME.hi_fg("c")}{THEME.title("olors")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 68:
Key.mouse["g"] = [[sort_pos - 32 + i, y-1] for i in range(8)]
out_misc += (f'{Mv.to(y-1, sort_pos - 33)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_gradient else ""}{THEME.hi_fg("g")}'
f'{THEME.title("radient")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 78:
Key.mouse["o"] = [[sort_pos - 42 + i, y-1] for i in range(8)]
out_misc += (f'{Mv.to(y-1, sort_pos - 43)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_per_core else ""}'
if w > 55 + s_len:
Key.mouse["o"] = [[sort_pos - 24 + i, y-1] for i in range(8)]
out_misc += (f'{Mv.to(y-1, sort_pos - 25)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_per_core else ""}'
f'{THEME.title("per-c")}{THEME.hi_fg("o")}{THEME.title("re")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 65 + s_len:
Key.mouse["g"] = [[sort_pos - 34 + i, y-1] for i in range(8)]
out_misc += (f'{Mv.to(y-1, sort_pos - 35)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_gradient else ""}{THEME.hi_fg("g")}'
f'{THEME.title("radient")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if w > 73 + s_len:
Key.mouse["c"] = [[sort_pos - 42 + i, y-1] for i in range(6)]
out_misc += (f'{Mv.to(y-1, sort_pos - 43)}{THEME.proc_box(Symbol.title_left)}{Fx.b if CONFIG.proc_colors else ""}'
f'{THEME.hi_fg("c")}{THEME.title("olors")}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
Key.mouse["f"] = [[x+9 + i, y-1] for i in range(6 if not proc.search_filter else 2 + len(proc.search_filter[-10:]))]
if proc.search_filter:
Key.mouse["delete"] = [[x+12 + len(proc.search_filter[-10:]) + i, y-1] for i in range(3)]
elif "delete" in Key.mouse:
del Key.mouse["delete"]
out_misc += (f'{Mv.to(y-1, x + 8)}{THEME.proc_box(Symbol.title_left)}{Fx.b if cls.filtering or proc.search_filter else ""}{THEME.hi_fg("f")}{THEME.title}' +
("ilter" if not proc.search_filter and not cls.filtering else f' {proc.search_filter[-(10 if w < 83 else w - 74):]}{(Fx.bl + "" + Fx.ubl) if cls.filtering else THEME.hi_fg(" del")}') +
f'{THEME.proc_box(Symbol.title_right)}')
Draw.buffer("proc_misc", out_misc, only_save=True)
@ -1886,18 +1924,25 @@ class ProcBox(Box):
if selected == "memory": selected = "mem"
if selected == "threads" and not CONFIG.proc_tree and not arg_len: selected = "tr"
if CONFIG.proc_tree:
out += f'{THEME.title}{Fx.b}{Mv.to(y, x)}{" Tree:":<{tree_len-2}}' "Threads: " f'{"User:":<9}Mem%{"Cpu%":>11}{Fx.ub}{THEME.main_fg}'
out += (f'{THEME.title}{Fx.b}{Mv.to(y, x)}{" Tree:":<{tree_len-2}}' "Threads: " f'{"User:":<9}Mem%{"Cpu%":>11}{Fx.ub}{THEME.main_fg} ' +
(" " if proc.num_procs > cls.select_max else ""))
if selected in ["program", "arguments"]: selected = "tree"
else:
out += (f'{THEME.title}{Fx.b}{Mv.to(y, x)}{"Pid:":>7} {"Program:" if prog_len > 8 else "Prg:":<{prog_len}}' + (f'{"Arguments:":<{arg_len-4}}' if arg_len else "") +
f'{"Threads:" if arg_len else " Tr:"} {"User:":<9}Mem%{"Cpu%":>11}{Fx.ub}{THEME.main_fg}')
f'{"Threads:" if arg_len else " Tr:"} {"User:":<9}Mem%{"Cpu%":>11}{Fx.ub}{THEME.main_fg} ' +
(" " if proc.num_procs > cls.select_max else ""))
if selected == "program" and prog_len <= 8: selected = "prg"
selected = selected.split(" ")[0].capitalize()
out = out.replace(selected, f'{Fx.u}{selected}{Fx.uu}')
cy = 1
if cls.start > proc.num_procs - cls.select_max + 1: cls.start = proc.num_procs - cls.select_max + 1 if proc.num_procs > cls.select_max else 0
if cls.selected > cls.select_max: cls.selected = cls.select_max
if cls.start > proc.num_procs - cls.select_max + 1 and proc.num_procs > cls.select_max: cls.start = proc.num_procs - cls.select_max + 1
elif cls.start > proc.num_procs: cls.start = proc.num_procs
if cls.start < 1: cls.start = 1
if cls.selected > proc.num_procs and proc.num_procs < cls.select_max: cls.selected = proc.num_procs
elif cls.selected > cls.select_max: cls.selected = cls.select_max
if cls.selected < 0: cls.selected = 0
for n, (pid, items) in enumerate(proc.processes.items(), start=1):
if n < cls.start: continue
@ -1939,6 +1984,8 @@ class ProcBox(Box):
else:
vals += [f'{THEME.gradient["cpu"][v if v <= 100 else 100]}']
c_color, m_color, t_color = vals
else:
c_color = m_color = t_color = Fx.b
if CONFIG.proc_gradient and not is_selected:
g_color = f'{THEME.gradient["proc"][calc * 100 // cls.select_max]}'
if is_selected:
@ -1951,21 +1998,34 @@ class ProcBox(Box):
t_color + (f'{threads:>4} ' if threads < 1000 else "999> ") + end +
g_color + (f'{username:<9.9}' if len(username) < 10 else f'{username[:8]:<8}+') +
m_color + (f'{mem:>4.1f}' if mem < 100 else f'{mem:>4.0f} ') + end +
f' {THEME.inactive_fg}{""*5}{THEME.main_fg}{g_color}{c_color}' + (f' {cpu:>4.1f} ' if cpu < 100 else f'{cpu:>5.0f} ') + end)
f' {THEME.inactive_fg}{""*5}{THEME.main_fg}{g_color}{c_color}' + (f' {cpu:>4.1f} ' if cpu < 100 else f'{cpu:>5.0f} ') + end +
(" " if proc.num_procs > cls.select_max else ""))
if pid in Graphs.pid_cpu:
if is_selected: c_color = THEME.proc_misc
#if is_selected: c_color = THEME.proc_misc
out += f'{Mv.to(y+cy, x + w - 11)}{c_color if CONFIG.proc_colors else THEME.proc_misc}{Graphs.pid_cpu[pid](None if cls.moved else round(cpu))}{THEME.main_fg}'
if selected: out += f'{Fx.ub}{Term.fg}{Term.bg}'
if is_selected: out += f'{Fx.ub}{Term.fg}{Term.bg}{Mv.to(y+cy, x + w - 1)}{" " if proc.num_procs > cls.select_max else ""}'
cy += 1
if cy == h: break
if cy < h:
for i in range(h-cy):
out += f'{Mv.to(y+cy+i, x)}{" " * w}'
loc_string = f'{cls.start + cls.selected - 1}/{len(proc.processes)}'
loc_string = f'{cls.start + cls.selected - 1}/{proc.num_procs}'
out += (f'{Mv.to(y+h, x + w - 15 - len(loc_string))}{THEME.proc_box}{Symbol.h_line*10}{Symbol.title_left}{THEME.title}'
f'{Fx.b}{loc_string}{Fx.ub}{THEME.proc_box(Symbol.title_right)}')
if proc.num_procs > cls.select_max:
Key.mouse["mouse_scroll_up"] = [[x+w-1, y]]
Key.mouse["mouse_scroll_down"] = [[x+w-1, y+h-1]]
scroll_pos = round(cls.start * (cls.select_max - 2) / (proc.num_procs - (cls.select_max - 2)))
if scroll_pos < 0 or cls.start == 1: scroll_pos = 0
elif scroll_pos > h - 3 or cls.start >= proc.num_procs - cls.select_max: scroll_pos = h - 3
out += (f'{Mv.to(y, x+w-1)}{Fx.b}{THEME.main_fg}{Mv.to(y+h-1, x+w-1)}{Fx.ub}'
f'{Mv.to(y+1+scroll_pos, x+w-1)}')
elif "scroll_up" in Key.mouse:
del Key.mouse["scroll_up"], Key.mouse["scroll_down"]
#▼▲ ↓ ↑
cls.count += 1
if cls.count == 100:
cls.count == 0
@ -1992,6 +2052,7 @@ class Collector:
collect_done = threading.Event()
collect_queue: List = []
collect_interrupt: bool = False
proc_interrupt: bool = False
use_draw_list: bool = False
@classmethod
@ -2045,15 +2106,18 @@ class Collector:
cls.collect_done.set()
except Exception as e:
errlog.exception(f'Data collection thread failed with exception: {e}')
cls.collect_idle.set()
cls.collect_done.set()
clean_quit(1, thread=True)
@classmethod
def collect(cls, *collectors, draw_now: bool = True, interrupt: bool = False, redraw: bool = False, only_draw: bool = False):
def collect(cls, *collectors, draw_now: bool = True, interrupt: bool = False, proc_interrupt: bool = False, redraw: bool = False, only_draw: bool = False):
'''Setup collect queue for _runner'''
cls.collect_interrupt = interrupt
cls.proc_interrupt = proc_interrupt
cls.collect_idle.wait()
cls.collect_interrupt = False
cls.proc_interrupt = False
cls.use_draw_list = False
cls.draw_now = draw_now
cls.redraw = redraw
@ -2411,6 +2475,7 @@ class NetCollector(Collector):
elif cls.nic_i < 0: cls.nic_i = len(cls.nics) - 1
cls.new_nic = cls.nics[cls.nic_i]
cls.switched = True
Collector.collect(NetCollector, redraw=True)
@classmethod
def _collect(cls):
@ -2505,9 +2570,11 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
search_filter: str = ""
processes: Dict = {}
num_procs: int = 0
detailed: bool = False
details: Dict[str, Union[str, int, float, NamedTuple]] = {}
details_cpu: List[int] = []
proc_dict: Dict = {}
p_values: List[str] = ["pid", "name", "cmdline", "num_threads", "username", "memory_percent", "cpu_percent", "cpu_times", "create_time"]
sorting_index: int = Config.sorting_options.index(CONFIG.proc_sorting)
sort_expr: Dict = {}
sort_expr["pid"] = compile("p.info['pid']", "str", "eval")
sort_expr["program"] = compile("p.info['name']", "str", "eval")
@ -2529,6 +2596,39 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
err: float = 0.0
n: int = 0
if cls.detailed and not cls.details.get("killed", False):
try:
det = psutil.Process(ProcBox.selected_pid)
except (psutil.NoSuchProcess, psutil.ZombieProcess):
cls.details["killed"] = True
cls.details["status"] = psutil.STATUS_DEAD
else:
cls.details = det.as_dict(attrs=["pid", "name", "username", "status", "cmdline", "memory_info", "memory_percent", "create_time", "num_threads", "cpu_percent", "cpu_num"], ad_value="")
if det.parent() != None: cls.details["parent_name"] = det.parent().name()
else: cls.details["parent_name"] = ""
cls.details["killed"] = False
if isinstance(cls.details["cmdline"], list): cls.details["cmdline"] = " ".join(cls.details["cmdline"]) or f'[{cls.details["name"]}]'
if hasattr(cls.details["memory_info"], "rss"): cls.details["memory_bytes"] = floating_humanizer(cls.details["memory_info"].rss) # type: ignore
else: cls.details["memory_bytes"] = "? Bytes"
if isinstance(cls.details["create_time"], float): cls.details["uptime"] = f'{timedelta(seconds=round(time()-cls.details["create_time"],0))}'
else: cls.details["uptime"] = "??:??:??"
for v in ["cpu_percent", "memory_percent"]:
if isinstance(cls.details[v], float):
if cls.details[v] >= 100: cls.details[v] = round(cls.details[v]) # type: ignore
elif cls.details[v] >= 10: cls.details[v] = round(cls.details[v], 1) # type: ignore
else: cls.details[v] = round(cls.details[v], 2) # type: ignore
else:
cls.details[v] = 0.0
cls.details_cpu.append(round(cls.details["cpu_percent"])) # type: ignore
if len(cls.details_cpu) > ProcBox.width: del cls.details_cpu[0]
if CONFIG.proc_tree and sorting == "arguments":
sorting = "program"
@ -2539,7 +2639,7 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
return
for p in sorted(psutil.process_iter(cls.p_values, err), key=lambda p: eval(sort_cmd), reverse=reverse):
if cls.collect_interrupt:
if cls.collect_interrupt or cls.proc_interrupt:
return
if p.info["name"] == "idle" or p.info["name"] == err or p.info["pid"] == err:
continue
@ -2593,7 +2693,6 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
else:
infolist[p.pid] = p.info
n += 1
cls.num_procs = n
if 0 in tree and 0 in tree[0]:
tree[0].remove(0)
@ -2609,6 +2708,7 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
except psutil.Error:
pass
cont = False
name = ""
if pid in infolist:
getinfo = infolist[pid]
else:
@ -2655,15 +2755,16 @@ class ProcCollector(Collector): #! add interrupt on _collect and _draw
create_tree(min(tree), tree)
if cls.collect_interrupt: return
cls.num_procs = len(out)
cls.processes = out.copy()
@classmethod
def sorting(cls, key: str):
cls.sorting_index += 1 if key == "right" else -1
if cls.sorting_index >= len(CONFIG.sorting_options): cls.sorting_index = 0
elif cls.sorting_index < 0: cls.sorting_index = len(CONFIG.sorting_options) - 1
CONFIG.proc_sorting = CONFIG.sorting_options[cls.sorting_index]
ProcBox.redraw = True
index: int = CONFIG.sorting_options.index(CONFIG.proc_sorting) + (1 if key == "right" else -1)
if index >= len(CONFIG.sorting_options): index = 0
elif index < 0: index = len(CONFIG.sorting_options) - 1
CONFIG.proc_sorting = CONFIG.sorting_options[index]
Collector.collect(ProcCollector, interrupt=True, redraw=True)
@classmethod
def _draw(cls):
@ -2955,6 +3056,7 @@ def floating_humanizer(value: Union[float, int], bit: bool = False, per_second:
if isinstance(value, float): value = round(value * 100 * mult)
elif value > 0: value *= 100 * mult
else: value = 0
while len(f'{value}') > 5 and value >= 102400:
value >>= 10
@ -2979,14 +3081,37 @@ def floating_humanizer(value: Union[float, int], bit: bool = False, per_second:
return out
def process_keys():
mouse_pos: Tuple[int, int]
mouse_pos: Tuple[int, int] = (0, 0)
filtered: bool = False
while Key.has_key():
key = Key.get()
if key in ["mouse_scroll_up", "mouse_scroll_down"]:
if key in ["mouse_scroll_up", "mouse_scroll_down", "mouse_click"]:
mouse_pos = Key.get_mouse()
if mouse_pos[0] >= ProcBox.x and mouse_pos[1] >= ProcBox.y:
if mouse_pos[0] >= ProcBox.x and mouse_pos[1] >= ProcBox.current_y:
pass
else: key = "_null"
elif key == "mouse_click":
key = "mouse_unselect"
else:
key = "_null"
if ProcBox.filtering:
if key in ["enter", "mouse_click", "mouse_unselect"]:
ProcBox.filtering = False
Collector.collect(ProcCollector, redraw=True, only_draw=True)
continue
elif key in ["escape", "delete"]:
ProcCollector.search_filter = ""
ProcBox.filtering = False
elif len(key) == 1:
ProcCollector.search_filter += key
elif key == "backspace" and len(ProcCollector.search_filter) > 0:
ProcCollector.search_filter = ProcCollector.search_filter[:-1]
else:
continue
Collector.collect(ProcCollector, proc_interrupt=True, redraw=True)
if filtered: Collector.collect_done.wait(0.1)
filtered = True
continue
if key == "_null":
@ -3001,7 +3126,6 @@ def process_keys():
Box.draw_update_ms()
elif key in ["b", "n"]:
NetCollector.switch(key)
Collector.collect(NetCollector, redraw=True)
elif key in ["m", "escape"]:
Menu.main()
elif key == "z":
@ -3009,7 +3133,6 @@ def process_keys():
Collector.collect(NetCollector)
elif key in ["left", "right"]:
ProcCollector.sorting(key)
Collector.collect(ProcCollector, interrupt=True, redraw=True)
elif key == "e":
CONFIG.proc_tree = not CONFIG.proc_tree
Collector.collect(ProcCollector, interrupt=True, redraw=True)
@ -3027,27 +3150,30 @@ def process_keys():
Collector.collect(ProcCollector, interrupt=True, redraw=True)
elif key == "h":
CONFIG.mem_graphs = not CONFIG.mem_graphs
Collector.collect(MemCollector, redraw=True)
Collector.collect(MemCollector, interrupt=True, redraw=True)
elif key == "p":
CONFIG.swap_disk = not CONFIG.swap_disk
Collector.collect(MemCollector, redraw=True)
elif key in ["up", "down", "mouse_scroll_up", "mouse_scroll_down", "page_up", "page_down", "home", "end"]:
if ProcBox.selector(key):
Collector.collect(ProcCollector, only_draw=True)
#? Main function --------------------------------------------------------------------------------->
def main():
Term.refresh()
Timer.stamp()
while Timer.not_zero():
if Key.input_wait(Timer.left()) and not Menu.active:
process_keys()
Collector.collect()
Collector.collect(MemCollector, interrupt=True, redraw=True)
elif key == "f":
ProcBox.filtering = True
if not ProcCollector.search_filter: ProcBox.start = 0
Collector.collect(ProcCollector, redraw=True, only_draw=True)
elif key == "delete" and ProcCollector.search_filter:
ProcCollector.search_filter = ""
Collector.collect(ProcCollector, proc_interrupt=True, redraw=True)
elif key == "enter" and ProcBox.selected > 0:
if ProcCollector.details.get("pid", None) == ProcBox.selected_pid:
ProcCollector.detailed = False
elif psutil.pid_exists(ProcBox.selected_pid):
ProcCollector.detailed = True
else:
continue
ProcCollector.details = {}
ProcCollector.details_cpu = []
Collector.collect(ProcCollector, proc_interrupt=True, redraw=True)
# Draw.buffer("!mouse_pos", f'{Key.mouse_pos}', z=0)
elif key in ["up", "down", "mouse_scroll_up", "mouse_scroll_down", "page_up", "page_down", "home", "end", "mouse_click", "mouse_unselect"]:
ProcBox.selector(key, mouse_pos)
#? Pre main -------------------------------------------------------------------------------------->
@ -3085,12 +3211,14 @@ if __name__ == "__main__":
Draw.buffer("initbg", z=10)
for i in range(51):
for _ in range(2): cls.initbg_colors.append(Color.fg(i, i, i))
Draw.buffer("banner", f'{Banner.draw(Term.height // 2 - 10, center=True)}{Color.fg("#50")}\n', z=2)
Draw.buffer("banner", (f'{Banner.draw(Term.height // 2 - 10, center=True)}{Mv.d(1)}{Mv.l(11)}{Colors.black_bg}{Colors.default}'
f'{Fx.b}{Fx.i}Version: {VERSION}{Fx.ui}{Fx.ub}{Term.bg}{Term.fg}{Color.fg("#50")}'), z=2)
for _i in range(7):
perc = f'{str(round((_i + 1) * 14 + 2)) + "%":>5}'
Draw.buffer("+banner", f'{Mv.to(Term.height // 2 - 3 + _i, Term.width // 2 - 28)}{Fx.trans(perc)}{Symbol.v_line}')
Draw.buffer("+banner", f'{Mv.to(Term.height // 2 - 2 + _i, Term.width // 2 - 28)}{Fx.trans(perc)}{Symbol.v_line}')
Draw.out("banner")
Draw.buffer("+init!", f'{Color.fg("#cc")}{Fx.b}{Mv.to(Term.height // 2 - 3, Term.width // 2 - 21)}{Mv.save}')
Draw.buffer("+init!", f'{Color.fg("#cc")}{Fx.b}{Mv.to(Term.height // 2 - 2, Term.width // 2 - 21)}{Mv.save}')
cls.initbg_data = [randint(0, 100) for _ in range(Term.width * 2)]
cls.initbg_up = Graph(Term.width, Term.height // 2, cls.initbg_colors, cls.initbg_data, invert=True)
@ -3098,8 +3226,7 @@ if __name__ == "__main__":
if start: return
cls.draw_bg(5)
cls.draw_bg(10)
Draw.buffer("+init!", f'{Mv.restore}{Symbol.ok}\n{Mv.r(Term.width // 2 - 22)}{Mv.save}')
@classmethod
@ -3117,14 +3244,13 @@ if __name__ == "__main__":
if cls.resized:
Draw.now(Term.clear)
else:
cls.draw_bg(15)
Draw.clear("initbg", "banner", "init")
cls.draw_bg(20)
Draw.clear("initbg", "banner", "init", saved=True)
del cls.initbg_up, cls.initbg_down, cls.initbg_data, cls.initbg_colors
#? Switch to alternate screen, clear screen, hide cursor and disable input echo
#? Switch to alternate screen, clear screen, hide cursor, enable mouse reporting and disable input echo
Draw.now(Term.alt_screen, Term.clear, Term.hide_cursor, Term.mouse_on)
Term.echo(False)
Term.refresh()
@ -3212,13 +3338,25 @@ if __name__ == "__main__":
Draw.out(clear=True)
if DEBUG: TimeIt.stop("Init")
#? Main loop ------------------------------------------------------------------------------------->
def main():
while not False:
Term.refresh()
Timer.stamp()
while Timer.not_zero():
if Key.input_wait(Timer.left()) and not Menu.active:
process_keys()
Collector.collect()
#? Start main loop
while not False:
try:
main()
except Exception as e:
errlog.exception(f'{e}')
clean_quit(1)
try:
main()
except Exception as e:
errlog.exception(f'{e}')
clean_quit(1)
else:
#? Quit cleanly even if false starts being true...
clean_quit()

Loading…
Cancel
Save