11 changed files with 3590 additions and 1 deletions
@ -0,0 +1,2 @@
|
||||
from .terminal import * |
||||
from .vt102 import * |
||||
@ -0,0 +1,171 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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, pty, threading |
||||
import re |
||||
from select import select |
||||
from TermTk.TTkCore.canvas import TTkCanvas |
||||
|
||||
|
||||
from TermTk.TTkCore.color import TTkColor |
||||
from TermTk.TTkCore.log import TTkLog |
||||
from TermTk.TTkCore.constant import TTkK |
||||
from TermTk.TTkCore.cfg import TTkCfg |
||||
from TermTk.TTkCore.string import TTkString |
||||
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot |
||||
from TermTk.TTkCore.helper import TTkHelper |
||||
from TermTk.TTkGui.clipboard import TTkClipboard |
||||
from TermTk.TTkGui.textwrap1 import TTkTextWrap |
||||
from TermTk.TTkGui.textcursor import TTkTextCursor |
||||
from TermTk.TTkGui.textdocument import TTkTextDocument |
||||
from TermTk.TTkLayouts.gridlayout import TTkGridLayout |
||||
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea |
||||
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout |
||||
from TermTk.TTkWidgets.widget import TTkWidget |
||||
|
||||
from .terminal_alt import _TTkTerminalAltScreen |
||||
from .terminal_normal import _TTkTerminalNormalScreen |
||||
|
||||
from .vt102 import TTkVT102 |
||||
|
||||
__all__ = ['TTkTerminal'] |
||||
|
||||
class TTkTerminal(TTkWidget): |
||||
__slots__ = ('_shell', '_fd', '_inout', '_mode_normal' |
||||
'_buffer_lines', '_buffer_screen', |
||||
'_screen_current', '_screen_normal', '_screen_alt') |
||||
def __init__(self, *args, **kwargs): |
||||
self._shell = os.environ.get('SHELL', 'sh') |
||||
self._fd = None |
||||
self._mode_normal = True |
||||
self._buffer_lines = [TTkString()] |
||||
self._screen_normal = _TTkTerminalNormalScreen() |
||||
self._screen_alt = _TTkTerminalAltScreen() |
||||
self._screen_current = self._screen_normal |
||||
|
||||
super().__init__(*args, **kwargs) |
||||
|
||||
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus) |
||||
|
||||
def runShell(self, program=None): |
||||
self._shell = program if program else self._shell |
||||
|
||||
pid, self._fd = pty.fork() |
||||
|
||||
if pid == 0: |
||||
argv = [self._shell] |
||||
env = dict(TERM="screen", DISPLAY=":1") |
||||
os.execvpe(argv[0], argv, env) |
||||
else: |
||||
self._inout = os.fdopen(self._fd, "w+b", 0) |
||||
name = os.ttyname(self._fd) |
||||
TTkLog.debug(f"{self._fd=} {name}") |
||||
|
||||
threading.Thread(target=self.loop,args=[self]).start() |
||||
|
||||
# xterm escape sequences from: |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ |
||||
re_CURSOR = re.compile('^(\d*)(;?)(\d*)([@ABCDEFGIJKLMPSTXZ^`abcdeginqx])') |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ |
||||
# Basic Re for CSI Ps matches: |
||||
# CSI : Control Sequence Introducer "<ESC>[" = '\033[' |
||||
# Ps : A single (usually optional) numeric parameter, composed of one or more digits. |
||||
# fn : the single char defining the function |
||||
re_CSI_Ps_fu = re.compile('^(\d*)([@ABCDEFGIJKLMPSTXZ^`abcdeginqx])') |
||||
re_CSI_Ps_Ps_fu = re.compile('^(\d*);(\d*)([Hf])') |
||||
re_DEC_SET_RST = re.compile('^\?(\d+)([lh])') |
||||
# re_CURSOR_1 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZHf])') |
||||
|
||||
def _process_cursor_match(self, m): |
||||
y = ps = m.group(1) |
||||
sep = m.group(2) |
||||
x = m.group(3) |
||||
fn = m.group(4) |
||||
_ex = self._screen_current._CSI_MAP.get(fn,lambda a,b,c: None) |
||||
_ex(self._screen_current,y,x) |
||||
|
||||
def loop(self, _): |
||||
while rs := select( [self._inout], [], [])[0]: |
||||
TTkLog.debug(f"Select - {rs=}") |
||||
for r in rs: |
||||
if r is self._inout: |
||||
try: |
||||
out = self._inout.read(10240) |
||||
except Exception as e: |
||||
TTkLog.error(f"Error: {e=}") |
||||
return |
||||
if out: |
||||
# TTkLog.debug(f'Eugenio->{out}') |
||||
sout = out.decode('utf-8','ignore') |
||||
sout = sout.split('\033[') |
||||
self._screen_current.pushLine(sout[0]) |
||||
TTkLog.debug(f"{sout[0]=}") |
||||
for slice in sout[1:]: |
||||
if m := TTkTerminal.re_DEC_SET_RST.match(slice): |
||||
# l = len(m.group(0)) |
||||
en = m.end() |
||||
ps = int(m.group(1)) |
||||
sr = m.group(2) |
||||
if ps == 1049 and sr == 'l': # NORMAL SCREEN |
||||
self._screen_current = self._screen_normal |
||||
elif ps == 1049 and sr == 'h': # ALT SCREEN |
||||
self._screen_current = self._screen_alt |
||||
elif ps == 2004: |
||||
# Bracketedpaste ON |
||||
# Bracketedpaste OFF |
||||
pass |
||||
slice = slice[en:] |
||||
elif m := TTkTerminal.re_CURSOR.match(slice): |
||||
TTkLog.debug(f"{m.group(0)=} {m.group(1)=} {m.group(2)=}") |
||||
en = m.end() |
||||
self._process_cursor_match(m) |
||||
slice[en:] |
||||
else: |
||||
slice = '\033[' + slice.replace('\r','') |
||||
|
||||
# TTkLog.debug(f'Eugenio->{slice}') |
||||
self._screen_current.pushLine(slice) |
||||
slice = slice.replace('\033','<ESC>').replace('\n','\\n') |
||||
TTkLog.debug(f"{slice=}") |
||||
self.update() |
||||
|
||||
def mousePressEvent(self, evt): |
||||
return True |
||||
|
||||
def keyEvent(self, evt): |
||||
# TTkLog.debug(f"Key: {evt.code=}") |
||||
TTkLog.debug(f"Key: {str(evt)=}") |
||||
self._inout.write(evt.code.encode()) |
||||
if evt.type == TTkK.SpecialKey: |
||||
if evt.key == TTkK.Key_Enter: |
||||
TTkLog.debug(f"Key: Enter") |
||||
# self._inout.write(b'\n') |
||||
# self._inout.write(evt.code.encode()) |
||||
else: # Input char |
||||
TTkLog.debug(f"Key: {evt.key=}") |
||||
# self._inout.write(evt.key.encode()) |
||||
return True |
||||
|
||||
def paintEvent(self, canvas: TTkCanvas): |
||||
w,h = self.size() |
||||
self._screen_current.paintEvent(canvas,w,h) |
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,46 @@
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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. |
||||
|
||||
from TermTk.TTkCore.color import TTkColor |
||||
from TermTk.TTkCore.log import TTkLog |
||||
from TermTk.TTkCore.constant import TTkK |
||||
from TermTk.TTkCore.cfg import TTkCfg |
||||
from TermTk.TTkCore.string import TTkString |
||||
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot |
||||
from TermTk.TTkCore.helper import TTkHelper |
||||
from TermTk.TTkGui.clipboard import TTkClipboard |
||||
from TermTk.TTkGui.textwrap1 import TTkTextWrap |
||||
from TermTk.TTkGui.textcursor import TTkTextCursor |
||||
from TermTk.TTkGui.textdocument import TTkTextDocument |
||||
from TermTk.TTkLayouts.gridlayout import TTkGridLayout |
||||
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea |
||||
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout |
||||
from TermTk.TTkWidgets.widget import TTkWidget |
||||
|
||||
__all__ = ['TTkVT102'] |
||||
|
||||
class TTkVT102(): |
||||
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 |
||||
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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. |
||||
|
||||
# This test is based on: |
||||
# pyte - In memory VTXXX-compatible terminal emulator. |
||||
# Terminal Emulator Example |
||||
# https://github.com/selectel/pyte/blob/master/examples/terminal_emulator.py |
||||
# |
||||
# pty — Pseudo-terminal utilities¶ |
||||
# https://docs.python.org/3/library/pty.html#example |
||||
# |
||||
# Using a pseudo-terminal to interact with interactive Python in a subprocess |
||||
# by Thomas Billinger |
||||
# https://gist.github.com/thomasballinger/7979808 |
||||
# |
||||
# Run interactive Bash with popen and a dedicated TTY Python |
||||
# https://stackoverflow.com/questions/41542960/run-interactive-bash-with-popen-and-a-dedicated-tty-python |
||||
|
||||
import os |
||||
import pty |
||||
import sys |
||||
import threading |
||||
from select import select |
||||
|
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'..')) |
||||
import TermTk as ttk |
||||
|
||||
ttk.TTkLog.use_default_file_logging() |
||||
root = ttk.TTk() |
||||
|
||||
wlog = ttk.TTkWindow(parent=root,pos = (32,12), size=(90,20), title="Log Window", flags=ttk.TTkK.WindowFlag.WindowCloseButtonHint|ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) |
||||
wlog.setLayout(ttk.TTkHBoxLayout()) |
||||
ttk.TTkLogViewer(parent=wlog, follow=False ) |
||||
|
||||
win1 = ttk.TTkWindow(parent=root, pos=(1,1), size=(70,15), title="Terminallo n.1", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) |
||||
term1 = ttk.TTkTerminal(parent=win1) |
||||
term1.runShell() |
||||
|
||||
win2 = ttk.TTkWindow(parent=root, pos=(10,5), size=(70,15), title="Terminallo n.2", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) |
||||
term2 = ttk.TTkTerminal(parent=win2) |
||||
term2.runShell() |
||||
|
||||
|
||||
root.mainloop() |
||||
@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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 sys, os |
||||
|
||||
import timeit |
||||
import re |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
|
||||
# Testing a string contain different kind of matches |
||||
# Uppercase the matching pattern |
||||
# With the one mimic the VT100 escape codes "A...x" |
||||
testString1 = ( |
||||
"123456Aabcdef01" + "A[123A" + |
||||
"123456Babcdef02" + "A[123B" + |
||||
"123456Babcdef03" + "A[12C" + |
||||
"123456Babcdef04" + "A[1D" + |
||||
"123456Babcdef05" + "A[?123l" + |
||||
"123456Babcdef06" + "A[?123h" + |
||||
"123456Babcdef07" + "A[?4l" + |
||||
"123456Babcdef08" + "A[?5h" + |
||||
"123456Babcdef09" + "A[1E" + |
||||
"123456Cabcdef10" + "A[1;3H" + |
||||
"123456Cabcdef11" + "A[;f" + |
||||
"123456Dabcdef12" + "A[123F" + |
||||
"123456Eabcdef13" + "A[12;34f" ) |
||||
|
||||
testString2 = ( |
||||
"123456Aabcdef01" + "A[123A" + |
||||
"123456Cabcdef10" + "A[1;3H" + |
||||
"123456Eabcdef13" ) |
||||
|
||||
testString3 = ( |
||||
"123456Aabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef01" + "A[123A" + |
||||
"123456Eabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef13" ) |
||||
|
||||
|
||||
re_P1_1 = re.compile(r'^(\d*);(\d*)([Hf])') |
||||
re_P1_2 = re.compile(r'^\?(\d+)([lh])') |
||||
re_P1_3 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZ])') |
||||
|
||||
def process1_1(txt): |
||||
_lines = [] |
||||
_cursor = (1,1) |
||||
lines = txt.split('A') |
||||
for i,l in enumerate(lines): |
||||
if i: |
||||
_lines.append("") |
||||
_cursor = (0,len(_lines)-1) |
||||
ls = l.split('B') |
||||
for ii,ll in enumerate(ls): |
||||
if ii: |
||||
_cursor = (0,len(_lines)-1) |
||||
lls = ll.split('C') |
||||
for iii,lll in enumerate(lls): |
||||
if iii: |
||||
x,y = _cursor |
||||
_cursor = (max(0,x-1),y) |
||||
_lines.append(lll) |
||||
return len(lines) +_cursor[0] + _cursor[1] |
||||
|
||||
def process1(txt): |
||||
r = 0 |
||||
tmp = [] |
||||
sout = txt.split('A[') |
||||
r += process1_1(sout[0]) |
||||
for slice in sout[1:]: |
||||
if m := re_P1_2.match(slice): |
||||
l = len(m.group(0)) |
||||
ps = int(m.group(1)) |
||||
sr = m.group(2) |
||||
tmp.append((ps,sr)) |
||||
slice = slice[l:] |
||||
elif m := re_P1_1.match(slice): |
||||
l = len(m.group(0)) |
||||
y = m.group(1) |
||||
x = m.group(2) |
||||
tp = m.group(3) |
||||
tmp.append((y,x,tp)) |
||||
slice = slice[l:] |
||||
elif m := re_P1_3.match(slice): |
||||
l = len(m.group(0)) |
||||
ps = int(m.group(1)) |
||||
sr = m.group(2) |
||||
tmp.append((ps,sr)) |
||||
slice = slice[l:] |
||||
else: |
||||
slice = '\033[' + slice.replace('\r','') |
||||
r += process1_1(slice) |
||||
return r + len(tmp) |
||||
|
||||
re_P2_1 = re.compile(r'A\[(\d*);(\d*)([Hf])') |
||||
re_P2_2 = re.compile(r'A\[\?(\d+)([lh])') |
||||
re_P2_3 = re.compile(r'A\[(\d+)([ABCDEFGIJKLMPSTXZ])') |
||||
re_P2_4 = re.compile(r'[ABCD]') |
||||
|
||||
def process2_2(txt): |
||||
ret=0 |
||||
pos = 0 |
||||
prev = 0 |
||||
lll = len(txt) |
||||
x,y = 0,0 |
||||
xxx = { |
||||
"A":lambda :(x+1,y), |
||||
"B":lambda :(x-1,y), |
||||
"C":lambda :(x,y+1), |
||||
"D":lambda :(x,y-1), |
||||
} |
||||
while pos < lll: |
||||
if m := re_P2_4.search(txt,pos): |
||||
gr = m.group() |
||||
ln = 1 |
||||
st = m.start() |
||||
en = pos = st+1 |
||||
_x = xxx.get(gr,lambda :(x,y)) |
||||
x,y = _x() |
||||
ret += x+y |
||||
ret += len(txt[prev:st]) |
||||
prev = en |
||||
else: |
||||
ret += len(txt[prev:]) |
||||
break |
||||
return ret |
||||
|
||||
def process2_1(txt): |
||||
ret=0 |
||||
pos = 0 |
||||
prev = 0 |
||||
lll = len(txt) |
||||
while pos < lll: |
||||
if m := re_P2_1.search(txt,pos): |
||||
gr = m.group() |
||||
ln = len(gr) |
||||
st = m.start() |
||||
en = pos = m.end() |
||||
y = int(vv) if (vv:=m.group(1)) else 0 |
||||
x = int(vv) if (vv:=m.group(2)) else 0 |
||||
ty = m.group(3) |
||||
ret += x+y |
||||
ret += process2_2(txt[prev:st]) |
||||
prev = en |
||||
elif m := re_P2_3.search(txt,pos): |
||||
gr = m.group() |
||||
ln = len(gr) |
||||
st = m.start() |
||||
ps = int(m.group(1)) |
||||
sr = m.group(2) |
||||
en = pos = m.end() |
||||
ret += ps |
||||
ret += process2_2(txt[prev:st]) |
||||
prev = en |
||||
else: |
||||
ret += process2_2(txt[prev:]) |
||||
break |
||||
return ret |
||||
|
||||
def process2(txt): |
||||
ret=0 |
||||
pos = 0 |
||||
prev = 0 |
||||
lll = len(txt) |
||||
xxx = { |
||||
"A[123l":lambda x:len(x)+1, |
||||
"A[123l":lambda x:len(x)+2, |
||||
} |
||||
while pos < lll: |
||||
if m := re_P2_2.search(txt,pos): |
||||
gr = m.group() |
||||
ln = len(gr) |
||||
st = m.start() |
||||
en = pos = m.end() |
||||
_x = xxx.get(gr,lambda x:len(x)+3) |
||||
ret += _x(txt[st:en]) |
||||
ret += process2_1(txt[prev:st]) |
||||
prev = en |
||||
else: |
||||
ret += process2_1(txt[prev:]) |
||||
break |
||||
return ret |
||||
|
||||
|
||||
def test1(): return process1(testString1) |
||||
def test2(): return process1(testString2) |
||||
def test3(): return process1(testString3) |
||||
def test4(): return process2(testString1) |
||||
def test5(): return process2(testString2) |
||||
def test6(): return process2(testString3) |
||||
def test7(): return 7 |
||||
def test8(): return 8 |
||||
def test9(): return 9 |
||||
|
||||
loop = 10000 |
||||
|
||||
a={} |
||||
|
||||
iii = 1 |
||||
while (testName := f'test{iii}') and (testName in globals()): |
||||
result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop) |
||||
# print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}") |
||||
print(f"test{iii:02}) | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}") |
||||
iii+=1 |
||||
|
||||
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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 sys, os |
||||
|
||||
import timeit |
||||
import re |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
|
||||
# Testing a string contain different kind of matches |
||||
# Uppercase the matching pattern |
||||
# With the one mimic the VT100 escape codes "A...x" |
||||
testString1 = "A[12;3H" + "abc" |
||||
testString2 = "A[123A" + "abc" |
||||
testString3 = "A[;f" + "abc" |
||||
|
||||
# xterm escape sequences from: |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ |
||||
re_CURSOR = re.compile('^A\[(\d*);?(\d*)([ABCDEFGIJKLMPSTXZHf@])') |
||||
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ |
||||
# Basic Re for CSI Ps matches: |
||||
# CSI : Control Sequence Introducer "<ESC>[" = '\033[' |
||||
# Ps : A single (usually optional) numeric parameter, composed of one or more digits. |
||||
# fu : the single char defining the function |
||||
re_CSI_Ps_fu = re.compile('^A\[(\d*)([ABCDEFGIJKLMPSTXZ@])') |
||||
re_CSI_Ps_Ps_fu = re.compile('^A\[(\d*);(\d*)([Hf])') |
||||
|
||||
re_CSI_Mix = re.compile('^A\[(\d*)([ABCDEFGIJKLMPSTXZ@])|A\[(\d*);(\d*)([Hf])') |
||||
|
||||
|
||||
re_DEC_SET_RST = re.compile('A\[\?(\d+)([lh])') |
||||
# re_CURSOR_1 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZHf])') |
||||
|
||||
def process1(txt): |
||||
if m:=re_CURSOR.match(txt): |
||||
return 1 |
||||
return 3 |
||||
|
||||
def process2(txt): |
||||
if m:=re_CSI_Ps_fu.match(txt): |
||||
return 1 |
||||
elif m:=re_CSI_Ps_Ps_fu.match(txt): |
||||
return 2 |
||||
return 3 |
||||
|
||||
def process3(txt): |
||||
if m:=re_CSI_Mix.match(txt): |
||||
return 1 |
||||
return 3 |
||||
|
||||
def test1(): return process1(testString1) |
||||
def test2(): return process1(testString2) |
||||
def test3(): return process1(testString3) |
||||
def test4(): return process2(testString1) |
||||
def test5(): return process2(testString2) |
||||
def test6(): return process2(testString3) |
||||
def test7(): return process3(testString1) |
||||
def test8(): return process3(testString2) |
||||
def test9(): return process3(testString3) |
||||
|
||||
loop = 100000 |
||||
|
||||
a={} |
||||
|
||||
iii = 1 |
||||
while (testName := f'test{iii}') and (testName in globals()): |
||||
result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop) |
||||
# print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}") |
||||
print(f"test{iii:02}) | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}") |
||||
iii+=1 |
||||
|
||||
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# MIT License |
||||
# |
||||
# Copyright (c) 2023 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 sys, os |
||||
|
||||
import timeit |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
|
||||
D1 = { |
||||
'a' : lambda x, _ : 2*x, |
||||
'b' : lambda x, _ : 2*x, |
||||
'c' : lambda x, _ : 2*x, |
||||
'd' : lambda x, _ : 2*x, |
||||
'e' : lambda x, _ : 2*x, |
||||
'f' : lambda x, _ : 2*x, |
||||
'g' : lambda x, _ : 2*x, |
||||
'h' : lambda x, _ : 2*x, |
||||
'i' : lambda x, _ : 2*x, |
||||
'j' : lambda x, _ : 2*x, |
||||
'k' : lambda x, _ : 2*x, |
||||
'l' : lambda x, y : 2*x+y, |
||||
'm' : lambda x, _ : 2*x, |
||||
'n' : lambda x, _ : 2*x, |
||||
'o' : lambda x, _ : 2*x, |
||||
'p' : lambda x, y : 2*x+y, |
||||
'q' : lambda x, _ : 2*x, |
||||
'r' : lambda x, _ : 2*x, |
||||
's' : lambda x, y : 2*x+y, |
||||
't' : lambda x, _ : 2*x, |
||||
'u' : lambda x, y : 2*x+y, |
||||
'v' : lambda x, _ : 2*x, |
||||
'w' : lambda x, _ : 2*x, |
||||
'x' : lambda x, _ : 2*x, |
||||
'y' : lambda x, _ : 2*x, |
||||
'z' : lambda x, _ : 2*x, |
||||
} |
||||
|
||||
D2_1 = { |
||||
'a' : lambda x: 2*x, |
||||
'b' : lambda x: 2*x, |
||||
'c' : lambda x: 2*x, |
||||
'd' : lambda x: 2*x, |
||||
'e' : lambda x: 2*x, |
||||
'f' : lambda x: 2*x, |
||||
'g' : lambda x: 2*x, |
||||
'h' : lambda x: 2*x, |
||||
'i' : lambda x: 2*x, |
||||
'j' : lambda x: 2*x, |
||||
'k' : lambda x: 2*x, |
||||
'm' : lambda x: 2*x, |
||||
'n' : lambda x: 2*x, |
||||
'o' : lambda x: 2*x, |
||||
'q' : lambda x: 2*x, |
||||
'r' : lambda x: 2*x, |
||||
't' : lambda x: 2*x, |
||||
'v' : lambda x: 2*x, |
||||
'w' : lambda x: 2*x, |
||||
'x' : lambda x: 2*x, |
||||
'y' : lambda x: 2*x, |
||||
'z' : lambda x: 2*x, |
||||
} |
||||
|
||||
D2_2 = { |
||||
'l' : lambda x, y : 2*x+y, |
||||
'p' : lambda x, y : 2*x+y, |
||||
's' : lambda x, y : 2*x+y, |
||||
'u' : lambda x, y : 2*x+y, |
||||
} |
||||
|
||||
test_input_1 = { |
||||
'a' : (2,None), |
||||
'b' : (2,None), |
||||
'c' : (2,None), |
||||
'd' : (2,None), |
||||
'e' : (2,None), |
||||
'l' : (2,2), |
||||
'p' : (2,2), |
||||
's' : (2,2), |
||||
'n' : (2,None), |
||||
'o' : (2,None), |
||||
'z' : (2,None), |
||||
'y' : (2,None), |
||||
'u' : (2,2), |
||||
} |
||||
|
||||
def process1(ttt): |
||||
ret = 0 |
||||
for i in ttt: |
||||
x,y = ttt[i] |
||||
_v = D1.get(i,lambda x,y:None) |
||||
ret += _v(x,y) |
||||
return ret |
||||
|
||||
def process2(ttt): |
||||
ret = 0 |
||||
for i in ttt: |
||||
x,y = ttt[i] |
||||
if y: |
||||
_v = D2_2.get(i,lambda x,y:None) |
||||
ret += _v(x,y) |
||||
else: |
||||
_v = D2_1.get(i,lambda x:None) |
||||
ret += _v(x) |
||||
return ret |
||||
|
||||
def process3(ttt): |
||||
return 3 |
||||
|
||||
def test1(): return process1(test_input_1) |
||||
def test2(): return process1(test_input_1) |
||||
def test3(): return process1(test_input_1) |
||||
def test4(): return process2(test_input_1) |
||||
def test5(): return process2(test_input_1) |
||||
def test6(): return process2(test_input_1) |
||||
def test7(): return process3(test_input_1) |
||||
def test8(): return process3(test_input_1) |
||||
def test9(): return process3(test_input_1) |
||||
|
||||
loop = 100000 |
||||
|
||||
a={} |
||||
|
||||
iii = 1 |
||||
while (testName := f'test{iii}') and (testName in globals()): |
||||
result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop) |
||||
# print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}") |
||||
print(f"test{iii:02}) | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}") |
||||
iii+=1 |
||||
|
||||
Loading…
Reference in new issue