Module TermTk.libbpytop.term
Expand source code
#!/usr/bin/env python3
# Copyright 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
# Copyright 2020 Aristocratos (https://github.com/aristocratos/bpytop)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os, sys, io, threading, signal, re, subprocess, logging, logging.handlers, argparse
import queue
from select import select
from time import time, sleep, strftime, localtime
from typing import List, Set, Dict, Tuple, Optional, Union, Any, Callable, ContextManager, Iterable, Type, NamedTuple
try: import fcntl, termios, tty, pwd
except Exception as e:
print(f'ERROR: {e}')
exit(1)
class Mv:
"""Class with collection of cursor movement functions: .t[o](line, column) | .r[ight](columns) | .l[eft](columns) | .u[p](lines) | .d[own](lines) | .save() | .restore()"""
@staticmethod
def to(line: int, col: int) -> str:
return f'\033[{line};{col}f' #* Move cursor to line, column
@staticmethod
def right(x: int) -> str: #* Move cursor right x columns
return f'\033[{x}C'
@staticmethod
def left(x: int) -> str: #* Move cursor left x columns
return f'\033[{x}D'
@staticmethod
def up(x: int) -> str: #* Move cursor up x lines
return f'\033[{x}A'
@staticmethod
def down(x: int) -> str: #* Move cursor down x lines
return f'\033[{x}B'
save: str = "\033[s" #* Save cursor position
restore: str = "\033[u" #* Restore saved cursor postion
t = to
r = right
l = left
u = up
d = down
class Term:
"""Terminal info and commands"""
title: str = "TermTk"
mouse: bool = True
width: int = 0
height: int = 0
fg: str = "" #* Default foreground color
bg: str = "" #* Default background color
hide_cursor = "\033[?25l" #* Hide terminal cursor
show_cursor = "\033[?25h" #* Show terminal cursor
alt_screen = "\033[?1049h" #* Switch to alternate screen
normal_screen = "\033[?1049l" #* Switch to normal screen
clear = "\033[2J\033[0;0f" #* Clear screen and set cursor to position 0,0
mouse_on = "\033[?1002h\033[?1015h\033[?1006h" #* Enable reporting of mouse position on click and release
mouse_off = "\033[?1002l" #* Disable mouse reporting
mouse_direct_on = "\033[?1003h" #* Enable reporting of mouse position at any movement
mouse_direct_off = "\033[?1003l" #* Disable direct mouse reporting
# from:
# https://superuser.com/questions/607478/how-do-you-change-the-xterm-cursor-to-an-i-beam-or-vertical-bar
# echo -e -n "\x1b[\x30 q" # changes to blinking block
# echo -e -n "\x1b[\x31 q" # changes to blinking block also
# echo -e -n "\x1b[\x32 q" # changes to steady block
# echo -e -n "\x1b[\x33 q" # changes to blinking underline
# echo -e -n "\x1b[\x34 q" # changes to steady underline
# echo -e -n "\x1b[\x35 q" # changes to blinking bar
# echo -e -n "\x1b[\x36 q" # changes to steady bar
cursor_blinking_block = "\033[\x30 q"
cursor_blinking_block_also = "\033[\x31 q"
cursor_steady_block = "\033[\x32 q"
cursor_blinking_underline = "\033[\x33 q"
cursor_steady_underline = "\033[\x34 q"
cursor_blinking_bar = "\033[\x35 q"
cursor_steady_bar = "\033[\x36 q"
_sigWinChCb = None
@staticmethod
def showCursor(cursor):
Term.push(cursor)
Term.push(Term.show_cursor)
@staticmethod
def hideCursor():
Term.push(Term.hide_cursor)
@staticmethod
def init(mouse: bool = True, title: str = "TermTk"):
Term.title = title
Term.mouse = mouse
Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title))
if Term.mouse:
Term.push(Term.mouse_on)
Term.echo(False)
@staticmethod
def stop():
Term.push(Term.mouse_off, Term.mouse_direct_off)
Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle())
Term.echo(True)
@staticmethod
def cont():
Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title))
if Term.mouse:
Term.push(Term.mouse_on)
Term.echo(False)
@staticmethod
def exit():
Term.push(Term.mouse_off, Term.mouse_direct_off)
Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle())
Term.echo(True)
@staticmethod
def echo(on: bool):
"""Toggle input echo"""
(iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(sys.stdin.fileno())
if on:
lflag |= termios.ECHO # type: ignore
else:
lflag &= ~termios.ECHO # type: ignore
new_attr = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, new_attr)
@staticmethod
def push(*args):
try:
print(*args, sep="", end="", flush=True)
except BlockingIOError:
pass
print(*args, sep="", end="", flush=True)
@staticmethod
def escTitle(text: str = "") -> str:
out: str = f'{os.environ.get("TERMINAL_TITLE", "")}'
if out and text: out += " "
if text: out += f'{text}'
return f'\033]0;{out}\a'
@staticmethod
def _sigWinCh(signum, frame):
Term.width, Term.height = os.get_terminal_size()
if Term._sigWinChCb is not None:
Term._sigWinChCb(Term.width, Term.height)
@staticmethod
def registerResizeCb(callback):
Term._sigWinChCb = callback
# Dummy call to retrieve the terminal size
Term._sigWinCh(signal.SIGWINCH, None)
signal.signal(signal.SIGWINCH, Term._sigWinCh)
Classes
class Mv-
Class with collection of cursor movement functions: .to | .right | .left | .up | .down | .save() | .restore()
Expand source code
class Mv: """Class with collection of cursor movement functions: .t[o](line, column) | .r[ight](columns) | .l[eft](columns) | .u[p](lines) | .d[own](lines) | .save() | .restore()""" @staticmethod def to(line: int, col: int) -> str: return f'\033[{line};{col}f' #* Move cursor to line, column @staticmethod def right(x: int) -> str: #* Move cursor right x columns return f'\033[{x}C' @staticmethod def left(x: int) -> str: #* Move cursor left x columns return f'\033[{x}D' @staticmethod def up(x: int) -> str: #* Move cursor up x lines return f'\033[{x}A' @staticmethod def down(x: int) -> str: #* Move cursor down x lines return f'\033[{x}B' save: str = "\033[s" #* Save cursor position restore: str = "\033[u" #* Restore saved cursor postion t = to r = right l = left u = up d = downSubclasses
Class variables
var restore : strvar save : str
Static methods
def d(x: int) ‑> str-
Expand source code
@staticmethod def down(x: int) -> str: #* Move cursor down x lines return f'\033[{x}B' def down(x: int) ‑> str-
Expand source code
@staticmethod def down(x: int) -> str: #* Move cursor down x lines return f'\033[{x}B' def l(x: int) ‑> str-
Expand source code
@staticmethod def left(x: int) -> str: #* Move cursor left x columns return f'\033[{x}D' def left(x: int) ‑> str-
Expand source code
@staticmethod def left(x: int) -> str: #* Move cursor left x columns return f'\033[{x}D' def r(x: int) ‑> str-
Expand source code
@staticmethod def right(x: int) -> str: #* Move cursor right x columns return f'\033[{x}C' def right(x: int) ‑> str-
Expand source code
@staticmethod def right(x: int) -> str: #* Move cursor right x columns return f'\033[{x}C' def t(line: int, col: int) ‑> str-
Expand source code
@staticmethod def to(line: int, col: int) -> str: return f'\033[{line};{col}f' #* Move cursor to line, column def to(line: int, col: int) ‑> str-
Expand source code
@staticmethod def to(line: int, col: int) -> str: return f'\033[{line};{col}f' #* Move cursor to line, column def u(x: int) ‑> str-
Expand source code
@staticmethod def up(x: int) -> str: #* Move cursor up x lines return f'\033[{x}A' def up(x: int) ‑> str-
Expand source code
@staticmethod def up(x: int) -> str: #* Move cursor up x lines return f'\033[{x}A'
class Term-
Terminal info and commands
Expand source code
class Term: """Terminal info and commands""" title: str = "TermTk" mouse: bool = True width: int = 0 height: int = 0 fg: str = "" #* Default foreground color bg: str = "" #* Default background color hide_cursor = "\033[?25l" #* Hide terminal cursor show_cursor = "\033[?25h" #* Show terminal cursor alt_screen = "\033[?1049h" #* Switch to alternate screen normal_screen = "\033[?1049l" #* Switch to normal screen clear = "\033[2J\033[0;0f" #* Clear screen and set cursor to position 0,0 mouse_on = "\033[?1002h\033[?1015h\033[?1006h" #* Enable reporting of mouse position on click and release mouse_off = "\033[?1002l" #* Disable mouse reporting mouse_direct_on = "\033[?1003h" #* Enable reporting of mouse position at any movement mouse_direct_off = "\033[?1003l" #* Disable direct mouse reporting # from: # https://superuser.com/questions/607478/how-do-you-change-the-xterm-cursor-to-an-i-beam-or-vertical-bar # echo -e -n "\x1b[\x30 q" # changes to blinking block # echo -e -n "\x1b[\x31 q" # changes to blinking block also # echo -e -n "\x1b[\x32 q" # changes to steady block # echo -e -n "\x1b[\x33 q" # changes to blinking underline # echo -e -n "\x1b[\x34 q" # changes to steady underline # echo -e -n "\x1b[\x35 q" # changes to blinking bar # echo -e -n "\x1b[\x36 q" # changes to steady bar cursor_blinking_block = "\033[\x30 q" cursor_blinking_block_also = "\033[\x31 q" cursor_steady_block = "\033[\x32 q" cursor_blinking_underline = "\033[\x33 q" cursor_steady_underline = "\033[\x34 q" cursor_blinking_bar = "\033[\x35 q" cursor_steady_bar = "\033[\x36 q" _sigWinChCb = None @staticmethod def showCursor(cursor): Term.push(cursor) Term.push(Term.show_cursor) @staticmethod def hideCursor(): Term.push(Term.hide_cursor) @staticmethod def init(mouse: bool = True, title: str = "TermTk"): Term.title = title Term.mouse = mouse Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title)) if Term.mouse: Term.push(Term.mouse_on) Term.echo(False) @staticmethod def stop(): Term.push(Term.mouse_off, Term.mouse_direct_off) Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle()) Term.echo(True) @staticmethod def cont(): Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title)) if Term.mouse: Term.push(Term.mouse_on) Term.echo(False) @staticmethod def exit(): Term.push(Term.mouse_off, Term.mouse_direct_off) Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle()) Term.echo(True) @staticmethod def echo(on: bool): """Toggle input echo""" (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(sys.stdin.fileno()) if on: lflag |= termios.ECHO # type: ignore else: lflag &= ~termios.ECHO # type: ignore new_attr = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, new_attr) @staticmethod def push(*args): try: print(*args, sep="", end="", flush=True) except BlockingIOError: pass print(*args, sep="", end="", flush=True) @staticmethod def escTitle(text: str = "") -> str: out: str = f'{os.environ.get("TERMINAL_TITLE", "")}' if out and text: out += " " if text: out += f'{text}' return f'\033]0;{out}\a' @staticmethod def _sigWinCh(signum, frame): Term.width, Term.height = os.get_terminal_size() if Term._sigWinChCb is not None: Term._sigWinChCb(Term.width, Term.height) @staticmethod def registerResizeCb(callback): Term._sigWinChCb = callback # Dummy call to retrieve the terminal size Term._sigWinCh(signal.SIGWINCH, None) signal.signal(signal.SIGWINCH, Term._sigWinCh)Class variables
var alt_screenvar bg : strvar clearvar cursor_blinking_barvar cursor_blinking_blockvar cursor_blinking_block_alsovar cursor_blinking_underlinevar cursor_steady_barvar cursor_steady_blockvar cursor_steady_underlinevar fg : strvar height : intvar hide_cursorvar mouse : boolvar mouse_direct_offvar mouse_direct_onvar mouse_offvar mouse_onvar normal_screenvar show_cursorvar title : strvar width : int
Static methods
def cont()-
Expand source code
@staticmethod def cont(): Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title)) if Term.mouse: Term.push(Term.mouse_on) Term.echo(False) def echo(on: bool)-
Toggle input echo
Expand source code
@staticmethod def echo(on: bool): """Toggle input echo""" (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(sys.stdin.fileno()) if on: lflag |= termios.ECHO # type: ignore else: lflag &= ~termios.ECHO # type: ignore new_attr = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, new_attr) def escTitle(text: str = '') ‑> str-
Expand source code
@staticmethod def escTitle(text: str = "") -> str: out: str = f'{os.environ.get("TERMINAL_TITLE", "")}' if out and text: out += " " if text: out += f'{text}' return f'\033]0;{out}\a' def exit()-
Expand source code
@staticmethod def exit(): Term.push(Term.mouse_off, Term.mouse_direct_off) Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle()) Term.echo(True) def hideCursor()-
Expand source code
@staticmethod def hideCursor(): Term.push(Term.hide_cursor) def init(mouse: bool = True, title: str = 'TermTk')-
Expand source code
@staticmethod def init(mouse: bool = True, title: str = "TermTk"): Term.title = title Term.mouse = mouse Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.escTitle(Term.title)) if Term.mouse: Term.push(Term.mouse_on) Term.echo(False) def push(*args)-
Expand source code
@staticmethod def push(*args): try: print(*args, sep="", end="", flush=True) except BlockingIOError: pass print(*args, sep="", end="", flush=True) def registerResizeCb(callback)-
Expand source code
@staticmethod def registerResizeCb(callback): Term._sigWinChCb = callback # Dummy call to retrieve the terminal size Term._sigWinCh(signal.SIGWINCH, None) signal.signal(signal.SIGWINCH, Term._sigWinCh) def showCursor(cursor)-
Expand source code
@staticmethod def showCursor(cursor): Term.push(cursor) Term.push(Term.show_cursor) def stop()-
Expand source code
@staticmethod def stop(): Term.push(Term.mouse_off, Term.mouse_direct_off) Term.push(Term.clear, Term.normal_screen, Term.show_cursor, Term.escTitle()) Term.echo(True)