Browse Source

Added basic Unicode special width support in TTkString and Canvas

pull/68/head
Eugenio Parodi 3 years ago
parent
commit
607980cac2
  1. 68
      TermTk/TTkCore/canvas.py
  2. 57
      TermTk/TTkCore/string.py
  3. 5
      TermTk/TTkWidgets/texedit.py
  4. 19
      demo/showcase/textedit.py
  5. 62
      tests/test.draw.006.py
  6. 7
      tests/test.metaclass.001.py
  7. 50
      tests/test.metaclass.002.py
  8. 1
      tests/timeit/.gitignore
  9. 88
      tests/timeit/00.template.py
  10. 18
      tests/timeit/05.wcwidth.bisearch.py
  11. 143
      tests/timeit/06.functionPointer.py
  12. 5
      tools/check.import.sh
  13. 56
      tools/gen.utf8.sizeMap.py

68
TermTk/TTkCore/canvas.py

@ -22,6 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import unicodedata
from TermTk.TTkCore.TTkTerm.term import TTkTerm
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.log import TTkLog
@ -29,7 +31,6 @@ from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.string import TTkString
class TTkCanvas:
''' Init the Canvas object
@ -178,6 +179,47 @@ class TTkCanvas:
x,y = pos
self._set(y, x, char, color)
def drawTTkString(self, pos, text, width=None, color=TTkColor.RST, alignment=TTkK.NONE, forceColor=False):
'''
NOTE:
drawText is one of the most abused functions,
there is some redundant code here in order to reduce the footprint
'''
if not self._visible: return
# Check the size and bounds
x,y = pos
if y<0 or y>=self._height : return
lentxt = text.termWidth()
if width is None or width<0:
width = lentxt
if x+width<0 or x>=self._width : return
text = text.align(width=width, alignment=alignment, color=color)
txt, colors = text.tab2spaces().getData()
if forceColor:
colors=[color]*len(colors)
a,b = max(0,-x), min(len(txt),self._width-x)
for i in range(a,b):
#self._set(y, x+i, txt[i-x], colors[i-x])
self._data[y][x+i] = txt[i]
if colors[i] == TTkColor.RST != color:
self._colors[y][x+i] = color.mod(x+i,y)
else:
self._colors[y][x+i] = colors[i].mod(x+i,y)
# Check the full wide chars on the edge of the two canvasses
wcColor = TTkColor.fg("#888888")+TTkColor.bg("000088")
if self._data[y][x+a] == '':
self._data[y][x+a] = '<'
self._colors[y][x+a] = wcColor
if ( len(ch:=self._data[y][x+b-1])==1
and unicodedata.east_asian_width(ch)=='W'):
self._data[y][x+b-1] = '>'
self._colors[y][x+b-1] = wcColor
def drawText(self, pos, text, width=None, color=TTkColor.RST, alignment=TTkK.NONE, forceColor=False):
'''
NOTE:
@ -598,9 +640,29 @@ class TTkCanvas:
wslice = w if x+w < bx+bw else bx+bw-x
hslice = h if y+h < by+bh else by+bh-y
wcColor = TTkColor.fg("#888888")+TTkColor.bg("000088")
for iy in range(yoffset,hslice):
self._data[y+iy][x+xoffset:x+wslice] = canvas._data[iy][xoffset:wslice]
self._colors[y+iy][x+xoffset:x+wslice] = canvas._colors[iy][xoffset:wslice]
a, b = x+xoffset, x+wslice
self._data[y+iy][a:b] = canvas._data[iy][xoffset:wslice]
self._colors[y+iy][a:b] = canvas._colors[iy][xoffset:wslice]
# Check the full wide chars on the edge of the two canvasses
if self._data[y+iy][a]=='':
self._data[y+iy][a] = '<'
self._colors[y+iy][a] = wcColor
if ( len(ch:=self._data[y+iy][b-1])==1
and unicodedata.east_asian_width(ch)=='W'):
self._data[y+iy][b-1] = '>'
self._colors[y+iy][b-1] = wcColor
if ( a and len(ch:=self._data[y+iy][a-1])==1
and unicodedata.east_asian_width(ch)=='W'):
self._data[y+iy][a-1] = '>'
self._colors[y+iy][a-1] = wcColor
if ( b<self._width-1 and self._data[y+iy][b]=='' ):
self._data[y+iy][b] = '<'
self._colors[y+iy][b] = wcColor
def pushToTerminal(self, x, y, w, h):
# TTkLog.debug("pushToTerminal")

57
TermTk/TTkCore/string.py

@ -23,6 +23,7 @@
# SOFTWARE.
import re
import unicodedata
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.color import TTkColor, _TTkColor
@ -56,7 +57,7 @@ class TTkString():
# Combination of constructors (Highly Unrecommended)
str7 = TTkString("test 7", color=TTkColor.fg('#FF0000'))
'''
__slots__ = ('_text','_colors','_baseColor','_hasTab')
__slots__ = ('_text','_colors','_baseColor','_hasTab','_hasSpecialWidth')
def __init__(self, text="", color=None):
if issubclass(type(text), TTkString):
@ -67,6 +68,7 @@ class TTkString():
self._baseColor = TTkColor.RST if color is None else color
self._text, self._colors = TTkString._parseAnsi(str(text), self._baseColor)
self._hasTab = '\t' in self._text
self._checkWidth()
# raise AttributeError(f"{type(text)} not supported in TTkString")
@staticmethod
@ -85,6 +87,12 @@ class TTkString():
colret += [color]*(len(text)-pos)
return txtret, colret
def termWidth(self):
if self._hasSpecialWidth:
return self._termWidthW()
else:
return len(self)
def __len__(self):
return len(self._text)
@ -106,6 +114,7 @@ class TTkString():
ret._colors = self._colors
ret._baseColor = other
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
def __radd__(self, other):
@ -118,6 +127,7 @@ class TTkString():
ret._text = other + self._text
ret._colors = [self._baseColor]*len(other) + self._colors
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
def __setitem__(self, index, value):
@ -139,6 +149,7 @@ class TTkString():
def setCharAt(self, pos, char):
self._text = self._text[:pos]+char+self._text[pos+1:]
self._checkWidth()
return self
def colorAt(self, pos):
@ -254,6 +265,7 @@ class TTkString():
ret._colors = self._colors[:width]
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
@ -301,6 +313,7 @@ class TTkString():
ret._text = self._text.replace(*args, **kwargs)
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
@ -321,6 +334,7 @@ class TTkString():
ret = TTkString()
ret._text += self._text
ret._hasTab = self._hasTab
ret._hasSpecialWidth = self._hasSpecialWidth
if match:
ret._colors += self._colors
start=0
@ -359,6 +373,7 @@ class TTkString():
ret = TTkString()
ret._text += self._text
ret._hasTab = self._hasTab
ret._hasSpecialWidth = self._hasSpecialWidth
if match:
ret._colors += self._colors
start=0
@ -389,6 +404,7 @@ class TTkString():
ret._text = self._text[fr:to]
ret._colors = self._colors[fr:to]
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
def split(self, separator ):
@ -413,7 +429,10 @@ class TTkString():
return ret
def getData(self):
return (self._text,self._colors)
if self._hasSpecialWidth:
return self._getDataW()
else:
return (tuple(self._text), self._colors)
def search(self, regexp, ignoreCase=False):
''' Return the **re.match** of the **regexp**
@ -450,3 +469,37 @@ class TTkString():
for s in strings[1:]:
ret += self + s
return ret
# Zero/Half/Normal sized chars helpers:
@staticmethod
def _isSpecialWidthChar(ch):
return ( unicodedata.east_asian_width(ch) == 'W' or
unicodedata.category(ch) in ('Me','Mn') )
def _checkWidth(self):
self._hasSpecialWidth = (
any(unicodedata.east_asian_width(ch) == 'W' for ch in self._text) or
any(unicodedata.category(ch) in ('Me','Mn') for ch in self._text) )
def _termWidthW(self):
''' String displayed length
This value consider the displayed size (Zero, Half, Full) of each character.
'''
return ( len(self._text) +
sum([unicodedata.east_asian_width(ch) == 'W' for ch in self._text]) -
sum([unicodedata.category(ch) in ('Me','Mn') for ch in self._text]) )
def _getDataW(self):
retTxt = []
retCol = []
for i,ch in enumerate(self._text):
if unicodedata.east_asian_width(ch) == 'W':
retTxt += (ch,'')
retCol += (self._colors[i],self._colors[i])
elif unicodedata.category(ch) in ('Me','Mn'):
retTxt[-1]+=ch
else:
retTxt.append(ch)
retCol.append(self._colors[i])
return (retTxt, retCol)

5
TermTk/TTkWidgets/texedit.py

@ -522,7 +522,7 @@ class TTkTextEditView(TTkAbstractScrollView):
for y, l in enumerate(subLines):
t = outLines[l[0]-subLines[0][0]]
self._canvas.drawText(pos=(-ox,y), text=t.substring(l[1][0],l[1][1]).tab2spaces(self._textWrap._tabSpaces))
self._canvas.drawTTkString(pos=(-ox,y), text=t.substring(l[1][0],l[1][1]).tab2spaces(self._textWrap._tabSpaces))
if self._lineWrapMode == TTkK.FixedWidth:
self._canvas.drawVLine(pos=(self._textWrap._wrapWidth,0), size=h, color=TTkCfg.theme.treeLineColor)
@ -533,7 +533,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
'_textEditView',
'_lineNumberView', '_lineNumber',
# Forwarded Methods
'clear', 'setText', 'append', 'isReadOnly', 'setReadOnly'
'clear', 'setText', 'append', 'isReadOnly', 'setReadOnly', 'document',
'wrapWidth', 'setWrapWidth',
'lineWrapMode', 'setLineWrapMode',
'wordWrapMode', 'setWordWrapMode',
@ -562,6 +562,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
self.clear = self._textEditView.clear
self.setText = self._textEditView.setText
self.append = self._textEditView.append
self.document = self._textEditView.document
self.isReadOnly = self._textEditView.isReadOnly
self.setReadOnly = self._textEditView.setReadOnly
self.textCursor = self._textEditView.textCursor

19
demo/showcase/textedit.py

@ -77,6 +77,25 @@ def demoTextEdit(root=None, document=None):
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)),'textedit.ANSI.txt')) as f:
te.append(f.read())
# Test Variable sized chars
te.append(ttk.TTkString("Test Variable sized chars\n",ttk.TTkColor.UNDERLINE+ttk.TTkColor.BOLD))
te.append( "Emoticons: -😁😂😍😎----")
te.append( " --😐😁😂😍😎-")
te.append("")
te.append( " UTF-8: £ @ £ ¬ ` 漢 _ _ あ _ _")
te.append( " |.|.|.|.|.||.|.|.||.|.|.")
te.append("")
zc1 = chr(0x07a6)
zc2 = chr(0x20D7)
zc3 = chr(0x065f)
te.append( " - | | | | | -")
te.append(f"Zero Size: - o{zc1} o{zc2} o{zc3} o{zc1}{zc2} o{zc1}{zc2}{zc3} -")
te.append( " - | | | | | -")
te.append("")
# Test Tabs
te.append(ttk.TTkString("Tabs Test\n",ttk.TTkColor.UNDERLINE+ttk.TTkColor.BOLD))
te.append("Word\tAnother Word\tYet more words")

62
tests/test.draw.006.py

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# 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 sys, os
import logging
import time
sys.path.append(os.path.join(sys.path[0],'..'))
from TermTk import TTkLog
from TermTk.TTkCore import TTkColor
from TermTk.TTkCore import TTkHelper
from TermTk.TTkCore import TTkString
from TermTk.TTkCore import TTkTerm
# TTkLog.use_default_file_logging()
TTkLog.use_default_stdout_logging()
# TTkTerm.init(mouse=False)
TTkLog.info("Starting")
s1 = TTkString("-😁😂😍😎----")
s2 = TTkString("--😐😁😂😍😎-")
zc1 = chr(0x07a6)
zc2 = chr(0x20D7)
zc3 = chr(0x065f)
s3 = TTkString(f"Zero Size: - o{zc1} o{zc2} o{zc3} o{zc1}{zc2} o{zc1}{zc2}{zc3} -")
s4 = TTkString("This is a notmal string")
print(s1.getData()[0])
print(s2.getData()[0])
print(s3.getData()[0])
print(s4.getData()[0])
# time.sleep(5)
TTkLog.info("Ending")
# TTkTerm.exit()

7
tests/test.metaclass.001.py

@ -21,7 +21,6 @@
# 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.
class A_Meta(type):
def __new__(mcs, name, bases, d):
print(f"{mcs=}")
@ -40,7 +39,7 @@ print(f"{A=}")
a = A(1,2,3,4)
print(f"{a=}\n")
print(f"A ---> {a=}\n")
class B(A_Meta):
def __init__(self, *args, **kwargs):
@ -50,7 +49,7 @@ class B(A_Meta):
b = B("NB",(),{})
print(f"{b=}\n")
print(f"B ---> {b=}\n")
class C():
def __init__(self) -> None:
@ -68,4 +67,4 @@ class E(C,D):
e = E()
e.pippo()
print(f"{issubclass(E,D)=} {issubclass(E,C)=}")
print(f"E,D ---> {issubclass(E,D)=} {issubclass(E,C)=}")

50
tests/test.metaclass.002.py

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# 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.
class A():
test = True
def __new__(cls, *args, **kwargs):
print(f"New: {args=} {kwargs=} {cls=}")
if kwargs.get('mod'):
return super().__new__(A_Mod)
return super().__new__(cls)
def __init__(self, *args, **kwargs):
print(f"Init: {args=} {kwargs=}")
class A_Mod(A):
test = False
def __init__(self, *args, **kwargs):
print(f"Init: Mod {args=} {kwargs=}")
a = A(1,2,3,aa=1,bb=2,cc=3)
print(f"A ---> {a=} {a.test=}")
b = A(1,2,3,aa=1,bb=2,cc=3,mod=4)
print(f"B ---> {b=} {b.test=}")
def test(x):
print(f"Test {x=}")
return x == 5
print(f"{any(test(x) for x in range(10))=}")

1
tests/timeit/.gitignore vendored

@ -0,0 +1 @@
wcwidth

88
tests/timeit/00.template.py

@ -0,0 +1,88 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 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 random
sys.path.append(os.path.join(sys.path[0],'../..'))
sys.path.append(os.path.join(sys.path[0],'.'))
import TermTk as ttk
def test1():
return 1
def test2():
return 1
def test3():
return 1
def test4():
return 1
def test5():
return 1
def test6():
return 1
def test7():
return 1
def test8():
return 1
def test9():
return 1
def test10():
return 1
def test11():
return 1
def test12():
return 1
loop = 100
result = timeit.timeit('test1()', globals=globals(), number=loop)
print(f"1 {result / loop:.10f} - {result / loop} {test1()}")
result = timeit.timeit('test2()', globals=globals(), number=loop)
print(f"2 {result / loop:.10f} - {result / loop} {test2()}")
result = timeit.timeit('test3()', globals=globals(), number=loop)
print(f"3 {result / loop:.10f} - {result / loop} {test3()}")
result = timeit.timeit('test4()', globals=globals(), number=loop)
print(f"4 {result / loop:.10f} - {result / loop} {test4()}")
result = timeit.timeit('test5()', globals=globals(), number=loop)
print(f"5 {result / loop:.10f} - {result / loop} {test5()}")
result = timeit.timeit('test6()', globals=globals(), number=loop)
print(f"6 {result / loop:.10f} - {result / loop} {test6()}")
result = timeit.timeit('test7()', globals=globals(), number=loop)
print(f"7 {result / loop:.10f} - {result / loop} {test7()}")
result = timeit.timeit('test8()', globals=globals(), number=loop)
print(f"8 {result / loop:.10f} - {result / loop} {test8()}")
result = timeit.timeit('test9()', globals=globals(), number=loop)
print(f"9 {result / loop:.10f} - {result / loop} {test9()}")
result = timeit.timeit('test10()', globals=globals(), number=loop)
print(f"10 {result / loop:.10f} - {result / loop} {test10()}")
result = timeit.timeit('test11()', globals=globals(), number=loop)
print(f"11 {result / loop:.10f} - {result / loop} {test11()}")
result = timeit.timeit('test12()', globals=globals(), number=loop)
print(f"12 {result / loop:.10f} - {result / loop} {test12()}")

18
tests/timeit/05.wcwidth.bisearch.py

@ -203,6 +203,20 @@ def test11():
sum([unicodedata.east_asian_width(ch) == 'W' for ch in cstr]) -
sum([unicodedata.category(ch) in ('Me','Mn') for ch in cstr]) )
def test12():
retTxt = []
retCol = []
for i,ch in enumerate(cstr):
if unicodedata.east_asian_width(ch) == 'W':
retTxt += (ch,'')
retCol += (ch,ch)
if unicodedata.category(ch) in ('Me','Mn'):
retTxt[-1]+=ch
else:
retTxt.append(ch)
retCol.append(ch)
return (len(retTxt), len(retCol))
loop = 100
@ -222,6 +236,10 @@ result = timeit.timeit('test8()', globals=globals(), number=loop)
print(f"8 {result / loop:.10f} - {result / loop} {test8()}")
result = timeit.timeit('test9()', globals=globals(), number=loop)
print(f"9 {result / loop:.10f} - {result / loop} {test9()}")
result = timeit.timeit('test12()', globals=globals(), number=loop)
print(f"12 {result / loop:.10f} - {result / loop} {test12()}")
result = timeit.timeit('test3()', globals=globals(), number=loop)
print(f"3w {result / loop:.10f} - {result / loop} {test3()}")

143
tests/timeit/06.functionPointer.py

@ -0,0 +1,143 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 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 random
sys.path.append(os.path.join(sys.path[0],'../..'))
sys.path.append(os.path.join(sys.path[0],'.'))
import TermTk as ttk
class A():
def test(self):
return 1
class B(A):
def test(self):
return 2
class C(B):
def test(self):
return 3
class D():
__slots__ = ('test')
def __init__(self, sw=True):
if sw:
self.test = self._testA
else:
self.test = self._testB
def _testA(self):
return 11
def _testB(self):
return 12
class E():
__slots__ = ('_sw')
def __init__(self, sw=True):
self._sw = sw
def test(self):
if self._sw:
return 21
else:
return 22
class F():
__slots__ = ('_sw')
def __init__(self, sw=True):
self._sw = sw
def test(self):
if self._sw:
return self._testA()
else:
return self._testB()
def _testA(self):
return 31
def _testB(self):
return 32
a = A()
b = B()
c = C()
da = D(sw=True)
db = D(sw=False)
ea = E(sw=True)
eb = E(sw=False)
fa = F(sw=True)
fb = F(sw=False)
def test1():
return a.test()
def test2():
return b.test()
def test3():
return c.test()
def test4():
return da.test()
def test5():
return db.test()
def test6():
return ea.test()
def test7():
return eb.test()
def test8():
return fa.test()
def test9():
return fb.test()
def test10(): return None
def test11(): return None
def test12(): return None
loop = 100000
result = timeit.timeit('test1()', globals=globals(), number=loop)
print(f"1a {result / loop:.10f} - {result / loop} {test1()}")
result = timeit.timeit('test2()', globals=globals(), number=loop)
print(f"2b {result / loop:.10f} - {result / loop} {test2()}")
result = timeit.timeit('test3()', globals=globals(), number=loop)
print(f"3c {result / loop:.10f} - {result / loop} {test3()}")
result = timeit.timeit('test4()', globals=globals(), number=loop)
print(f"4da {result / loop:.10f} - {result / loop} {test4()}")
result = timeit.timeit('test5()', globals=globals(), number=loop)
print(f"5db {result / loop:.10f} - {result / loop} {test5()}")
result = timeit.timeit('test6()', globals=globals(), number=loop)
print(f"6ea {result / loop:.10f} - {result / loop} {test6()}")
result = timeit.timeit('test7()', globals=globals(), number=loop)
print(f"7eb {result / loop:.10f} - {result / loop} {test7()}")
result = timeit.timeit('test8()', globals=globals(), number=loop)
print(f"8fa {result / loop:.10f} - {result / loop} {test8()}")
result = timeit.timeit('test9()', globals=globals(), number=loop)
print(f"9fb {result / loop:.10f} - {result / loop} {test9()}")
result = timeit.timeit('test10()', globals=globals(), number=loop)
print(f"10 {result / loop:.10f} - {result / loop} {test10()}")
result = timeit.timeit('test11()', globals=globals(), number=loop)
print(f"11 {result / loop:.10f} - {result / loop} {test11()}")
result = timeit.timeit('test12()', globals=globals(), number=loop)
print(f"12 {result / loop:.10f} - {result / loop} {test12()}")

5
tools/check.import.sh

@ -29,8 +29,9 @@ __check(){
-e "ttk.py:import platform" \
-e "clipboard.py:import importlib.util" \
-e "filebuffer.py:import threading" \
-e "texedit.py:from math import log10, ceil"
-e "texedit.py:from math import log10, ceil" \
-e "canvas.py:import unicodedata" \
-e "string.py:import unicodedata"
} ;
if __check ; then

56
tools/gen.utf8.sizeMap.py

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# 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 urllib.request
import re
URI='http://www.unicode.org/Public/UCD/latest/ucd/DerivedAge.txt'
response = urllib.request.urlopen(URI)
# Matching:
# "FE24..FE26 ; 5.1 # [3] COMBINING MACRON LEFT HALF..COMBINING CONJOINING MACRON"
# "10190..1019B ; 5.1 # [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN"
rangeMatch = re.compile(r'^([0-9A-F]+)\.\.([0-9A-F]+) *; ([0-9\.]+) (#.*)$')
# Matching:
# "A95F ; 5.1 # REJANG SECTION MARK"
# "1093F ; 5.1 # LYDIAN TRIANGULAR MARK"
singleMatch = re.compile(r'^([0-9A-F]+) *; ([0-9\.]+) (#.*)$')
for line in response.readlines():
# print(line.decode('utf-8'))
if m := rangeMatch.match(line.decode('utf-8')):
rfr = m.group(1)
rto = m.group(2)
rver = m.group(3)
rdesc = m.group(4)
print(f"{rver=} {rfr=} {rto=} {rdesc=}")
elif m := singleMatch.match(line.decode('utf-8')):
rm = m.group(1)
rver = m.group(2)
rdesc = m.group(3)
print(f"{rver=} {rm=} {rdesc=}")
Loading…
Cancel
Save