You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

156 lines
6.5 KiB

# MIT License
#
# Copyright (c) 2022 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import os
class TTkTermBase():
CLEAR = "\033[2J\033[0;0f" # Clear screen and set cursor to position 0,0
ALT_SCREEN = "\033[?1049h" #* Switch to alternate screen
NORMAL_SCREEN = "\033[?1049l" #* Switch to normal screen
SET_BRACKETED_PM = "\033[?2004h" # Ps = 2 0 0 4 ⇒ Set bracketed paste mode, xterm.
RESET_BRACKETED_PM = "\033[?2004l" # Ps = 2 0 0 4 ⇒ Reset bracketed paste mode, xterm.
class Mouse(str):
ON = "\033[?1002h\033[?1006h" # Enable reporting of mouse position on click and release
OFF = "\033[?1002l\033[?1006l" # Disable mouse reporting
DIRECT_ON = "\033[?1003h" # Enable reporting of mouse position at any movement
DIRECT_OFF = "\033[?1003l" # Disable direct mouse reporting
class Cursor(str):
# 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
BLINKING_BLOCK = "\033[\x30 q"
BLINKING_BLOCK_ALSO = "\033[\x31 q"
STEADY_BLOCK = "\033[\x32 q"
BLINKING_UNDERLINE = "\033[\x33 q"
STEADY_UNDERLINE = "\033[\x34 q"
BLINKING_BAR = "\033[\x35 q"
STEADY_BAR = "\033[\x36 q"
HIDE = "\033[?25l"
SHOW = "\033[?25h"
@staticmethod
def moveTo(y:int,x:int)->str: return f'\033[{y};{x}f'
@staticmethod
def moveRight(n:int)->str: return f'\033[{n}C'
@staticmethod
def moveLeft(n:int)->str: return f'\033[{n}D'
@staticmethod
def modeUp(n:int)->str: return f'\033[{n}A'
@staticmethod
def moveDown(n:int)->str: return f'\033[{n}B'
@staticmethod
def show(cursorType):
TTkTermBase.push(cursorType)
TTkTermBase.push(TTkTermBase.Cursor.SHOW)
@staticmethod
def hide():
TTkTermBase.push(TTkTermBase.Cursor.HIDE)
class Sigmask():
CTRL_C = 0x0001
CTRL_S = 0x0002
CTRL_Z = 0x0004
CTRL_Q = 0x0008
title: str = "TermTk"
width: int = 0
height: int = 0
mouse: bool = True
directMouse: bool = False
_sigWinChCb = None
@staticmethod
def init(title: str = "TermTk", sigmask=0) -> None:
TTkTermBase.title = title
TTkTermBase.Cursor.hide()
TTkTermBase.push(TTkTermBase.escTitle(TTkTermBase.title))
TTkTermBase.push(TTkTermBase.ALT_SCREEN)
TTkTermBase.push(TTkTermBase.SET_BRACKETED_PM)
TTkTermBase.push(TTkTermBase.CLEAR + TTkTermBase.Cursor.HIDE)
TTkTermBase.setEcho(False)
TTkTermBase.CRNL(False)
TTkTermBase.setSigmask(sigmask, False)
@staticmethod
def setMouse(mouse:bool=False, directMouse:bool=False) -> None:
TTkTermBase.mouse = mouse | directMouse
TTkTermBase.directMouse = directMouse
if TTkTermBase.mouse:
TTkTermBase.push(TTkTermBase.Mouse.DIRECT_OFF)
TTkTermBase.push(TTkTermBase.Mouse.ON)
if TTkTermBase.directMouse:
TTkTermBase.push(TTkTermBase.Mouse.DIRECT_ON)
else:
TTkTermBase.push(TTkTermBase.Mouse.OFF)
TTkTermBase.push(TTkTermBase.Mouse.DIRECT_OFF)
@staticmethod
def exit() -> None:
TTkTermBase.push(TTkTermBase.Mouse.OFF + TTkTermBase.Mouse.DIRECT_OFF)
TTkTermBase.push(TTkTermBase.CLEAR + TTkTermBase.NORMAL_SCREEN + TTkTermBase.RESET_BRACKETED_PM + TTkTermBase.Cursor.SHOW + TTkTermBase.escTitle())
TTkTermBase.setEcho(True)
TTkTermBase.CRNL(True)
@staticmethod
def stop() -> None:
TTkTermBase.push(TTkTermBase.Mouse.OFF + TTkTermBase.Mouse.DIRECT_OFF)
TTkTermBase.push(TTkTermBase.CLEAR + TTkTermBase.NORMAL_SCREEN + TTkTermBase.RESET_BRACKETED_PM + TTkTermBase.Cursor.SHOW + TTkTermBase.escTitle())
TTkTermBase.setEcho(True)
TTkTermBase.CRNL(True)
@staticmethod
def cont() -> None:
TTkTermBase.push(TTkTermBase.ALT_SCREEN + TTkTermBase.SET_BRACKETED_PM + TTkTermBase.CLEAR + TTkTermBase.Cursor.HIDE + TTkTermBase.escTitle(TTkTermBase.title))
TTkTermBase.setMouse(TTkTermBase.mouse, TTkTermBase.directMouse)
TTkTermBase.setEcho(False)
TTkTermBase.CRNL(False)
@staticmethod
def escTitle(txt = "") -> str:
tt = os.environ.get("TERMINAL_TITLE", "")
if tt and txt:
return f'\033]0;{tt} {txt}\a'
else:
return f'\033]0;{tt}{txt}\a'
# NOTE: Due to "I have no idea how to do it in a better way",
# those methods are supposed to be overwritten with the
# compatible one in "term_unix.py" or "term_pyodide.py"
setSigmask = lambda *args: None
push = lambda *args: None
flush = lambda *args: None
setEcho = lambda *args: None
CRNL = lambda *args: None
getTerminalSize = lambda *args: (80,24)
registerResizeCb = lambda *args: None