From 542ecd7f7798b10bca29a7e856e85aa91bb3bc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parodi=2C=20Eugenio=20=F0=9F=8C=B6?= Date: Fri, 4 Apr 2025 19:01:24 +0100 Subject: [PATCH] refactor: adapted ttkode to the latest pyTermTk --- apps/tlogg/Makefile | 35 ----- apps/ttkode/ttkode/__init__.py | 5 - apps/ttkode/ttkode/app/__init__.py | 2 +- apps/ttkode/ttkode/app/about.py | 6 +- apps/ttkode/ttkode/app/cfg.py | 2 + apps/ttkode/ttkode/app/kodeformatter.py | 142 ------------------ apps/ttkode/ttkode/app/kodetextdocument.py | 165 --------------------- apps/ttkode/ttkode/app/kodetextedit.py | 31 ---- apps/ttkode/ttkode/app/main.py | 103 +------------ apps/ttkode/ttkode/app/options.py | 2 + apps/ttkode/ttkode/app/ttkode.py | 119 +++++++++++++++ libs/pyTermTk/TermTk/TTkWidgets/about.py | 4 +- 12 files changed, 136 insertions(+), 480 deletions(-) delete mode 100644 apps/tlogg/Makefile delete mode 100644 apps/ttkode/ttkode/app/kodeformatter.py delete mode 100644 apps/ttkode/ttkode/app/kodetextdocument.py delete mode 100644 apps/ttkode/ttkode/app/kodetextedit.py create mode 100644 apps/ttkode/ttkode/app/ttkode.py diff --git a/apps/tlogg/Makefile b/apps/tlogg/Makefile deleted file mode 100644 index 36bfc4e0..00000000 --- a/apps/tlogg/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -.PHONY: doc runGittk runDemo build deploy buildTest deployTest - -.venv: - python3 -m venv .venv - . .venv/bin/activate ; \ - pip install -r docs/requirements.txt - # Regen requirements; - # pip freeze > docs/requirements.txt - -build: .venv - . .venv/bin/activate ; \ - rm -rf dist ; \ - tools/prepareBuild.sh release ; \ - cd tmp ; \ - python3 -m build - -buildTest: .venv - . .venv/bin/activate ; \ - rm -rf dist ; \ - tools/prepareBuild.sh test ; \ - cd tmp ; \ - python3 -m build ; - -deployTest: .venv - . .venv/bin/activate ; \ - python3 -m twine upload --repository testpypi tmp/dist/* --verbose - -deploy: .venv - . .venv/bin/activate ; \ - python3 -m twine upload tmp/dist/* --repository tlogg --verbose - -#test: .venv -# . .venv/bin/activate ; \ -# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude .venv,build,tmp ; \ -# pytest demo/demo.py diff --git a/apps/ttkode/ttkode/__init__.py b/apps/ttkode/ttkode/__init__.py index 65b77879..f0f5e076 100755 --- a/apps/ttkode/ttkode/__init__.py +++ b/apps/ttkode/ttkode/__init__.py @@ -23,8 +23,3 @@ # SOFTWARE. __version__:str = '0.2.15-a.2' - -from .app import * - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/apps/ttkode/ttkode/app/__init__.py b/apps/ttkode/ttkode/app/__init__.py index 3f68dd5f..936b7d49 100644 --- a/apps/ttkode/ttkode/app/__init__.py +++ b/apps/ttkode/ttkode/app/__init__.py @@ -25,5 +25,5 @@ from .cfg import * # from .glbl import * +from .ttkode import * from .main import * -from .kodetextdocument import KodeTextDocument \ No newline at end of file diff --git a/apps/ttkode/ttkode/app/about.py b/apps/ttkode/ttkode/app/about.py index 8e86da69..f8a507a3 100644 --- a/apps/ttkode/ttkode/app/about.py +++ b/apps/ttkode/ttkode/app/about.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - # MIT License # # Copyright (c) 2021 Eugenio Parodi @@ -22,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +__all__ = ['About'] + from TermTk.TTkCore.log import TTkLog from TermTk.TTkCore.color import TTkColor from TermTk import TTkAbout, TTkWindow @@ -47,6 +47,8 @@ class About(TTkAbout): def paintEvent(self, canvas): c = [0xFF,0xFF,0xFF] + for i,line in enumerate(TTkAbout._peppered_string.split('\n')): + canvas.drawTTkString(pos=(1,3+i), text=line) for y, line in enumerate(About.ttkode): canvas.drawText(pos=(13,3+y),text=line, color=TTkColor.fg(f'#{c[0]:02X}{c[1]:02X}{c[2]:02X}')) c[2]-=0x18 diff --git a/apps/ttkode/ttkode/app/cfg.py b/apps/ttkode/ttkode/app/cfg.py index b6ec872c..17f4c49c 100644 --- a/apps/ttkode/ttkode/app/cfg.py +++ b/apps/ttkode/ttkode/app/cfg.py @@ -22,6 +22,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +__all__ = ['TTKodeCfg'] + import os import json diff --git a/apps/ttkode/ttkode/app/kodeformatter.py b/apps/ttkode/ttkode/app/kodeformatter.py deleted file mode 100644 index dbd9a4de..00000000 --- a/apps/ttkode/ttkode/app/kodeformatter.py +++ /dev/null @@ -1,142 +0,0 @@ -# MIT License -# -# Copyright (c) 2022 Eugenio Parodi -# -# 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 pygments.formatter import Formatter -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Token, Whitespace - -from TermTk import TTkString, TTkColor, TTkLog - -#: Map token types to a tuple of color values for light and dark -#: backgrounds. -TTKODE_COLORS = { - Token: TTkColor.RST, # ('', ''), - - Whitespace: TTkColor.fg('#888888') , # ('gray', 'brightblack'), - Comment: TTkColor.fg('#888888') , # ('gray', 'brightblack'), - Comment.Preproc: TTkColor.fg('#00FFFF') , # ('cyan', 'brightcyan'), - Keyword: TTkColor.fg('#0000FF') , # ('blue', 'brightblue'), - Keyword.Type: TTkColor.fg('#00FFFF') , # ('cyan', 'brightcyan'), - Operator.Word: TTkColor.fg('#FF8800') , # ('magenta', 'brightmagenta'), - Name.Builtin: TTkColor.fg('#00FFFF') , # ('cyan', 'brightcyan'), - Name.Function: TTkColor.fg('#00FF00') , # ('green', 'brightgreen'), - Name.Namespace: TTkColor.fg('#00FFFF') , # ('_cyan_', '_brightcyan_'), - Name.Class: TTkColor.fg('#00FF00') , # ('_green_', '_brightgreen_'), - Name.Exception: TTkColor.fg('#00FFFF') , # ('cyan', 'brightcyan'), - Name.Decorator: TTkColor.fg('#888888') , # ('brightblack', 'gray'), - Name.Variable: TTkColor.fg('#888888') , # ('red', 'brightred'), - Name.Constant: TTkColor.fg('#888888') , # ('red', 'brightred'), - Name.Attribute: TTkColor.fg('#00FFFF') , # ('cyan', 'brightcyan'), - Name.Tag: TTkColor.fg('#0000FF') , # ('brightblue', 'brightblue'), - String: TTkColor.fg('#FFFF00') , # ('yellow', 'yellow'), - Number: TTkColor.fg('#0000FF') , # ('blue', 'brightblue'), - - Generic.Deleted: TTkColor.fg('#FF0000') , # ('brightred', 'brightred'), - Generic.Inserted: TTkColor.fg('#00FF00') , # ('green', 'brightgreen'), - Generic.Heading: TTkColor.fg('#888888') , # ('**', '**'), - Generic.Subheading: TTkColor.fg('#FF8800') , # ('*magenta*', '*brightmagenta*'), - Generic.Prompt: TTkColor.fg('#888888') , # ('**', '**'), - Generic.Error: TTkColor.fg('#FF0000') , # ('brightred', 'brightred'), - - Error: TTkColor.fg('#FF0000') , # ('_brightred_', '_brightred_'), -} - -class KodeFormatter(Formatter): - class Data(): - __slots__=('lines', 'block', 'error', 'multiline') - def __init__(self, lines, block): - self.lines = lines - self.block = block - self.error = None - self.multiline = False - - __slots__ = ('_dl', '_blockNum', '_kodeStyles') - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._kodeStyles = {} - self._blockNum = 1 - for token, style in self.style: - # Token = Token.Comment.PreprocFile - # style = { - # 'color': '6272a4', - # 'bgcolor': None, - # 'bold': False, 'italic': False, 'underline': False, - # 'border': None, - # 'roman': None, 'sans': None, 'mono': None, - # 'ansicolor': None, 'bgansicolor': None} - - # TTkLog.debug(f"{token=} {style=}") - color = TTkColor.RST - if style['color']: - color += TTkColor.fg(f"#{style['color']}") - if style['bgcolor']: - color += TTkColor.bg(f"#{style['bgcolor']}") - if style['bold']: - color += TTkColor.BOLD - if style['italic']: - color += TTkColor.ITALIC - if style['underline']: - color += TTkColor.UNDERLINE - self._kodeStyles[token] = color - - super().__init__() - - def setDl(self,dl): - self._dl = dl - - def format(self, tokensource, _): - multiline = False - multilineId = 0 - for ttype, value in tokensource: - if ttype == Error and self._dl.error is None: - self._dl.error = len(self._dl.lines)-1 - # self._dl.multiline = ttype == Comment.Multiline - multiline = ttype == Comment.Multiline - - while ttype not in self._kodeStyles: - ttype = ttype.parent - # TTkLog.debug (f"{ttype=}") - # TTkLog.debug (f"{value=}") - color = self._kodeStyles[ttype] - - values = value.split('\n') - - self._dl.lines[-1] += TTkString(values[0],color) - self._dl.lines += [TTkString(t,color) for t in values[1:]] - self._dl.block[-1] = self._blockNum - self._dl.block += [self._blockNum]*(len(values)-1) - - # self._dl.lines += [TTkString(t) for t in value.split('\n')] - - # multiline = len(values)>1 if self._dl.lines[-1]._text == values[-1] else self._dl.multiline - # if self._dl.lines[-1]._text == '' or not multiline: - # self._blockNum += 1 - # multilineId = len(self._dl.lines) - - if multiline: - multilineId += len(values) - else: - multilineId = 0 - self._blockNum += 1 - - if multiline: - self._dl.multiline = multilineId diff --git a/apps/ttkode/ttkode/app/kodetextdocument.py b/apps/ttkode/ttkode/app/kodetextdocument.py deleted file mode 100644 index 9c6f4e1b..00000000 --- a/apps/ttkode/ttkode/app/kodetextdocument.py +++ /dev/null @@ -1,165 +0,0 @@ -# MIT License -# -# Copyright (c) 2022 Eugenio Parodi -# -# 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 threading import Lock - -from pygments import highlight -from pygments.util import ClassNotFound -from pygments.lexers import guess_lexer, guess_lexer_for_filename, special -from pygments.formatters import TerminalFormatter, Terminal256Formatter, TerminalTrueColorFormatter - -from TermTk import TTk, TTkK, TTkLog, TTkCfg, TTkTheme, TTkTerm, TTkHelper, TTkTimer -from TermTk import TTkString -from TermTk import TTkColor, TTkColorGradient -from TermTk import pyTTkSlot, pyTTkSignal - -from TermTk import TTkTextDocument -from .kodeformatter import KodeFormatter - -class KodeTextDocument(TTkTextDocument): - _linesRefreshed = 30 - __slots__ = ( - '_filePath', '_timerRefresh', - 'kodeHighlightUpdate', '_kodeDocMutex', - '_blocks', '_changedContent', '_refreshContent', - '_lexer', '_formatter') - def __init__(self, filePath:str="", **kwargs): - self.kodeHighlightUpdate = pyTTkSignal() - self._kodeDocMutex = Lock() - self._lexer = None - self._blocks = [] - # self._formatter = KodeFormatter(style='dracula') - self._filePath = filePath - self._formatter = KodeFormatter(style='gruvbox-dark') - self._timerRefresh = TTkTimer() - super().__init__(**kwargs) - self._changedContent = (0,0,len(self._dataLines)) - self._refreshContent = (0,KodeTextDocument._linesRefreshed) - self._timerRefresh.timeout.connect(self._refreshEvent) - self._timerRefresh.start(0.3) - self.contentsChange.connect(lambda a,b,c: TTkLog.debug(f"{a=} {b=} {c=}")) - self.contentsChange.connect(self._saveChangedContent) - - @pyTTkSlot(int,int,int) - def _saveChangedContent(self,a,b,c): - if self._changedContent: - self._changedContent = TTkTextDocument._mergeChangesSlices(self._changedContent,(a,b,c)) - else: - self._changedContent = (a,b,c) - if not self._refreshContent: - self._refreshContent = (self._changedContent[0], KodeTextDocument._linesRefreshed) - self._timerRefresh.start(0.1) - - @pyTTkSlot() - def _refreshEvent(self): - if not self._refreshContent: return - self._kodeDocMutex.acquire() - - ra,rb = self._refreshContent - - if self._changedContent: - ca,cb,cc = self._changedContent - self._changedContent = None - self._blocks[ca:ca+cb] = [0]*cc - ra = min(ra,ca) - - # find the beginning of the current block - # TTkLog.debug(self._blocks) - if ra and self._blocks: - blockId = self._blocks[ra] - for i,v in enumerate(reversed(self._blocks[:ra])): - # TTkLog.debug(f"{i=}:{v=} {blockId=}") - if v == blockId or not blockId: - blockId = v - ra -= 1 - rb += 1 - else: - break - - # TTkLog.debug(f"{ra=} {rb=}") - - eof = False - if (ra+rb) >= len(self._dataLines): - rb = len(self._dataLines)-ra - eof=True - - tsl = self._dataLines[ra:ra+rb] - # Find the offset from the first not empty line - # because pygments autostrip the heading empty lines - offset = 0 - for i,l in enumerate(tsl): - if l != '': - offset = i - break - - rawl = [l._text for l in tsl[offset:]] - rawt = '\n'.join(rawl) - if not self._lexer: - try: - self._lexer = guess_lexer_for_filename(self._filePath, rawt) - except ClassNotFound: - self._lexer = special.TextLexer() - - # TTkLog.debug(f"Refresh {self._lexer.name} {ra=} {rb=}") - tsl1 = [TTkString()]*(offset+1) - block = [0]*(offset+1) - - kfd = KodeFormatter.Data(tsl1, block) - self._formatter.setDl(kfd) - - highlight(rawt, self._lexer, self._formatter) - - # for ll in tsl: - # TTkLog.debug(f"1: -{ll}-") - # for ll in tsl1: - # TTkLog.debug(f"2: -{ll}-") - - tsl1 = tsl1[:rb] - block = block[:rb] - self._dataLines[ra:ra+rb] = tsl1 + tsl[len(tsl1):] - self._blocks[ra:ra+rb] = block + [-1]*(rb-len(block)) - # TTkLog.debug(self._blocks) - - if kfd.error is not None: - self._refreshContent = (ra+kfd.error,rb<<1) - # TTkLog.debug(f"Error: {self._refreshContent=}") - elif kfd.multiline is not None: - self._refreshContent = (ra+kfd.multiline,rb<<1) - elif (ra+rb) < len(self._dataLines): - self._refreshContent = (ra+rb,KodeTextDocument._linesRefreshed) - else: - self._refreshContent = None - # TTkLog.debug(f"{self._refreshContent=}") - - if not eof: - self._timerRefresh.start(0.03) - else: - TTkLog.debug(f"Refresh {self._lexer.name} DONE!!!") - - self._kodeDocMutex.release() - self.kodeHighlightUpdate.emit() - - def getLock(self): - return self._kodeDocMutex - - def filePath(self): - return self._filePath \ No newline at end of file diff --git a/apps/ttkode/ttkode/app/kodetextedit.py b/apps/ttkode/ttkode/app/kodetextedit.py deleted file mode 100644 index 36d2c5a5..00000000 --- a/apps/ttkode/ttkode/app/kodetextedit.py +++ /dev/null @@ -1,31 +0,0 @@ -# MIT License -# -# Copyright (c) 2022 Eugenio Parodi -# -# 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 import TTkLog -from TermTk import TTkTextEditView - -class KodeTextEditView(TTkTextEditView): - def keyEvent(self, evt) -> bool: - self.document().getLock().acquire() - ret = super().keyEvent(evt) - self.document().getLock().release() - return ret \ No newline at end of file diff --git a/apps/ttkode/ttkode/app/main.py b/apps/ttkode/ttkode/app/main.py index c1db61b2..07f1f066 100644 --- a/apps/ttkode/ttkode/app/main.py +++ b/apps/ttkode/ttkode/app/main.py @@ -22,108 +22,17 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import os -import re -import sys +__all__ = ['main'] + import argparse import appdirs -from pygments import highlight -from pygments.lexers import PythonLexer -from pygments.formatters import TerminalFormatter, Terminal256Formatter, TerminalTrueColorFormatter - -from TermTk import TTk, TTkK, TTkLog, TTkCfg, TTkColor, TTkTheme, TTkTerm, TTkHelper -from TermTk import TTkString -from TermTk import TTkColorGradient -from TermTk import pyTTkSlot, pyTTkSignal - -from TermTk import TTkFrame, TTkButton -from TermTk import TTkTabWidget, TTkKodeTab -from TermTk import TTkAbstractScrollArea, TTkAbstractScrollView -from TermTk import TTkFileDialogPicker -from TermTk import TTkFileTree, TTkTextEdit - -from TermTk import TTkGridLayout -from TermTk import TTkSplitter - -from .cfg import * -from .about import * -# from .options import optionsFormLayout, optionsLoadTheme -from .kodetextedit import KodeTextEditView -from .kodetextdocument import KodeTextDocument - -class TTKode(TTkGridLayout): - __slots__ = ('_kodeTab', '_documents') - def __init__(self, *, files, **kwargs): - self._documents = {} - - super().__init__(**kwargs) - - self.addWidget(splitter := TTkSplitter()) - - layoutLeft = TTkGridLayout() - splitter.addItem(layoutLeft, 20) - - hSplitter = TTkSplitter(parent=splitter, orientation=TTkK.HORIZONTAL) - - menuFrame = TTkFrame(border=False, maxHeight=1) - - self._kodeTab = TTkKodeTab(parent=hSplitter, border=False, closable=True) - - fileMenu = menuFrame.newMenubarTop().addMenu("&File") - fileMenu.addMenu("Open").menuButtonClicked.connect(self._showFileDialog) - fileMenu.addMenu("Close") # .menuButtonClicked.connect(self._closeFile) - fileMenu.addMenu("Exit").menuButtonClicked.connect(lambda _:TTkHelper.quit()) - - def _showAbout(btn): - TTkHelper.overlay(None, About(), 30,10) - def _showAboutTTk(btn): - TTkHelper.overlay(None, TTkAbout(), 30,10) - - helpMenu = menuFrame.newMenubarTop().addMenu("&Help", alignment=TTkK.RIGHT_ALIGN) - helpMenu.addMenu("About ...").menuButtonClicked.connect(_showAbout) - helpMenu.addMenu("About ttk").menuButtonClicked.connect(_showAboutTTk) - - fileTree = TTkFileTree(path='.') - - layoutLeft.addWidget(menuFrame, 0,0) - layoutLeft.addWidget(fileTree, 1,0) - layoutLeft.addWidget(quitbtn := TTkButton(border=True, text="Quit", maxHeight=3), 2,0) - - quitbtn.clicked.connect(TTkHelper.quit) - - for file in files: - self._openFile(file) - - fileTree.fileActivated.connect(lambda x: self._openFile(x.path())) - - pyTTkSlot() - def _showFileDialog(self): - filePicker = TTkFileDialogPicker(pos = (3,3), size=(75,24), caption="Pick Something", path=".", fileMode=TTkK.FileMode.AnyFile ,filter="All Files (*);;Python Files (*.py);;Bash scripts (*.sh);;Markdown Files (*.md)") - filePicker.pathPicked.connect(self._openFile) - TTkHelper.overlay(None, filePicker, 20, 5, True) - - def _openFile(self, filePath): - filePath = os.path.realpath(filePath) - if filePath in self._documents: - doc = self._documents[filePath]['doc'] - else: - with open(filePath, 'r') as f: - content = f.read() - doc = KodeTextDocument(text=content, filePath=filePath) - self._documents[filePath] = {'doc':doc,'tabs':[]} - tview = KodeTextEditView(document=doc, readOnly=False) - tedit = TTkTextEdit(textEditView=tview, lineNumber=True) - doc.kodeHighlightUpdate.connect(tedit.update) - label = TTkString(TTkCfg.theme.fileIcon.getIcon(filePath),TTkCfg.theme.fileIconColor) + TTkColor.RST + " " + os.path.basename(filePath) - - self._kodeTab.addTab(tedit, label) - self._kodeTab.setCurrentWidget(tedit) +from TermTk import TTk, TTkTerm, TTkTheme +from TermTk import TTkLog - # def _closeFile(): - # if (index := KodeTab.lastUsed.currentIndex()) >= 0: - # KodeTab.lastUsed.removeTab(index) +from .ttkode import TTKode +from .cfg import TTKodeCfg def main(): TTKodeCfg.pathCfg = appdirs.user_config_dir("ttkode") diff --git a/apps/ttkode/ttkode/app/options.py b/apps/ttkode/ttkode/app/options.py index 7165b046..ad5862da 100644 --- a/apps/ttkode/ttkode/app/options.py +++ b/apps/ttkode/ttkode/app/options.py @@ -22,6 +22,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +__all__ = ['optionsLoadTheme', 'optionsFormLayout'] + import copy from . import TTKodeCfg, TloggGlbl diff --git a/apps/ttkode/ttkode/app/ttkode.py b/apps/ttkode/ttkode/app/ttkode.py new file mode 100644 index 00000000..accecf57 --- /dev/null +++ b/apps/ttkode/ttkode/app/ttkode.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# 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. + +__all__ = ['TTKode'] + +import os + +from TermTk import TTkK, TTkLog, TTkCfg, TTkColor, TTkTheme, TTkTerm, TTkHelper +from TermTk import TTkString +from TermTk import pyTTkSlot, pyTTkSignal + +from TermTk import TTkFrame, TTkButton +from TermTk import TTkKodeTab +from TermTk import TTkFileDialogPicker +from TermTk import TTkFileTree, TTkTextEdit + +from TermTk import TTkGridLayout +from TermTk import TTkSplitter +from TermTk import TextDocumentHighlight + +from .about import About + +class _TextDocument(TextDocumentHighlight): + __slots__ = ('_filePath') + def __init__(self, filePath:str="", **kwargs): + self._filePath = filePath + super().__init__(**kwargs) + self.guessLexerFromFilename(filePath) + +class TTKode(TTkGridLayout): + __slots__ = ('_kodeTab', '_documents') + def __init__(self, *, files, **kwargs): + self._documents = {} + + super().__init__(**kwargs) + + self.addWidget(splitter := TTkSplitter()) + + layoutLeft = TTkGridLayout() + splitter.addItem(layoutLeft, 20) + + hSplitter = TTkSplitter(parent=splitter, orientation=TTkK.HORIZONTAL) + + menuFrame = TTkFrame(border=False, maxHeight=1) + + self._kodeTab = TTkKodeTab(parent=hSplitter, border=False, closable=True) + + fileMenu = menuFrame.newMenubarTop().addMenu("&File") + fileMenu.addMenu("Open").menuButtonClicked.connect(self._showFileDialog) + fileMenu.addMenu("Close") # .menuButtonClicked.connect(self._closeFile) + fileMenu.addMenu("Exit").menuButtonClicked.connect(lambda _:TTkHelper.quit()) + + def _showAbout(btn): + TTkHelper.overlay(None, About(), 30,10) + def _showAboutTTk(btn): + TTkHelper.overlay(None, TTkAbout(), 30,10) + + helpMenu = menuFrame.newMenubarTop().addMenu("&Help", alignment=TTkK.RIGHT_ALIGN) + helpMenu.addMenu("About ...").menuButtonClicked.connect(_showAbout) + helpMenu.addMenu("About ttk").menuButtonClicked.connect(_showAboutTTk) + + fileTree = TTkFileTree(path='.') + + layoutLeft.addWidget(menuFrame, 0,0) + layoutLeft.addWidget(fileTree, 1,0) + layoutLeft.addWidget(quitbtn := TTkButton(border=True, text="Quit", maxHeight=3), 2,0) + + quitbtn.clicked.connect(TTkHelper.quit) + + for file in files: + self._openFile(file) + + fileTree.fileActivated.connect(lambda x: self._openFile(x.path())) + + pyTTkSlot() + def _showFileDialog(self): + filePicker = TTkFileDialogPicker(pos = (3,3), size=(75,24), caption="Pick Something", path=".", fileMode=TTkK.FileMode.AnyFile ,filter="All Files (*);;Python Files (*.py);;Bash scripts (*.sh);;Markdown Files (*.md)") + filePicker.pathPicked.connect(self._openFile) + TTkHelper.overlay(None, filePicker, 20, 5, True) + + def _openFile(self, filePath): + filePath = os.path.realpath(filePath) + if filePath in self._documents: + doc = self._documents[filePath]['doc'] + else: + with open(filePath, 'r') as f: + content = f.read() + doc = _TextDocument(text=content, filePath=filePath) + self._documents[filePath] = {'doc':doc,'tabs':[]} + tedit = TTkTextEdit(document=doc, readOnly=False, lineNumber=True) + label = TTkString(TTkCfg.theme.fileIcon.getIcon(filePath),TTkCfg.theme.fileIconColor) + TTkColor.RST + " " + os.path.basename(filePath) + + self._kodeTab.addTab(tedit, label) + self._kodeTab.setCurrentWidget(tedit) + + # def _closeFile(): + # if (index := KodeTab.lastUsed.currentIndex()) >= 0: + # KodeTab.lastUsed.removeTab(index) diff --git a/libs/pyTermTk/TermTk/TTkWidgets/about.py b/libs/pyTermTk/TermTk/TTkWidgets/about.py index 48d43964..f0d6c22b 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/about.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/about.py @@ -39,7 +39,6 @@ _peppered_image = TTkUtil.base64_deflate_2_obj( "5U2DXq3mDsvOfNqlvUa+RyTDOIh2FzT0BTmKSF6LuBkvvDOKPDpMvEXbHn1c6vRN2kpFuMgl9u2lXnzdyIBqxgR8Vh+GLZhjEoz1rDe3NTPOD+7TKdv/iBsvaPR+fnxK" + "xQDE4uRREkUJ66XbtrnsPzh2UpZrPsLpiuSfWR4dVb7jqa6eZJnJVIxboW48rdJF2ABxDMxk73q1GcaMFpv7wcfOF+RqZ89t+64LcTjIw8OTYYtVm3J7H3cB43I6aSq0" + "4Zf9GYaCzmMK1e6+dLH7AkxADRtZ3ojHUrmNqNtco9mqF7pzbppx0GQSQ3Op8FcJ2G5ltCNVLuI74ZeG5vr8rDHAaP/o5bQnnOawWcPyRePnp/8KRQkp") -_peppered_string = TTkString(_peppered_image) class TTkAbout(TTkWindow): ''' @@ -94,6 +93,7 @@ class TTkAbout(TTkWindow): [(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x21,0x00,0x00),(0x6c,0x00,0x00),(0xa2,0x00,0x00),(0x84,0x00,0x00),(0xe6,0x02,0x02),(0xff,0x3a,0x3a),(0xff,0x43,0x43),(0xec,0x05,0x04),(0x8f,0x00,0x00),(0x93,0x00,0x00),(0x65,0x00,0x00),(0x2b,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00)], [(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x0b,0x00,0x00),(0x29,0x00,0x00),(0x30,0x00,0x00),(0x4c,0x00,0x00),(0x95,0x00,0x00),(0xa0,0x00,0x00),(0x61,0x00,0x00),(0x1a,0x00,0x00),(0x10,0x00,0x00),(0x03,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00)], [(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00)]] + _peppered_string = TTkString(_peppered_image) pyTermTk = [ @@ -118,7 +118,7 @@ class TTkAbout(TTkWindow): for y, line in enumerate(TTkAbout.pyTermTk): canvas.drawText(pos=(9,3+y),text=line, color=TTkColor.fg(f'#{c[0]:02X}{c[1]:02X}{c[2]:02X}')) c[2]-=0x11 - for i,line in enumerate(_peppered_string.split('\n')): + for i,line in enumerate(TTkAbout._peppered_string.split('\n')): canvas.drawTTkString(pos=(1,3+i), text=line) canvas.drawText(pos=(20, 9),text=f" Version: {TTkCfg.version}", color=TTkColor.fg('#AAAAFF')) canvas.drawText(pos=(12,11),text=f"Powered By, Eugenio Parodi")