Browse Source

feat: improve search plugin (#389)

pull/393/head
Pier CeccoPierangioliEugenio 11 months ago committed by GitHub
parent
commit
09d190d5c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .vscode/launch.json
  2. 2
      apps/ttkode/ttkode/app/__init__.py
  3. 6
      apps/ttkode/ttkode/app/main.py
  4. 239
      apps/ttkode/ttkode/app/ttkode.py
  5. 35
      apps/ttkode/ttkode/plugins/_010/findwidget.py
  6. 15
      apps/ttkode/ttkode/proxy.py

2
.vscode/launch.json vendored

@ -113,7 +113,7 @@
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONPATH": "./apps/ttkode"
"PYTHONPATH": "./apps/ttkode:./libs/pyTermTk"
}
},
{

2
apps/ttkode/ttkode/app/__init__.py

@ -1,6 +1,4 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>

6
apps/ttkode/ttkode/app/main.py

@ -63,7 +63,7 @@ def main():
TTkodeHelper._loadPlugins()
ttkode = TTKode(files=args.filename)
ttkode = TTKode()
ttkodeProxy.setTTKode(ttkode)
root = TTk( layout=ttkode,
@ -73,8 +73,12 @@ def main():
# TTkTerm.Sigmask.CTRL_C |
TTkTerm.Sigmask.CTRL_Q |
TTkTerm.Sigmask.CTRL_S |
TTkTerm.Sigmask.CTRL_Y |
TTkTerm.Sigmask.CTRL_Z ))
for file in args.filename:
ttkodeProxy.openFile(file)
TTkodeHelper._runPlugins()
root.mainloop()

239
apps/ttkode/ttkode/app/ttkode.py

@ -1,5 +1,3 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
@ -25,31 +23,15 @@
__all__ = ['TTKode']
import os
from typing import List,Tuple,Optional,Any
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, TTkTextCursor
from TermTk import TTkGridLayout
from TermTk import TTkSplitter,TTkAppTemplate
from TermTk import TextDocumentHighlight
from TermTk import TTkLogViewer
from TermTk import TTkMenuBarLayout
from TermTk import TTkAbout
from TermTk import TTkTestWidget, TTkTestWidgetSizes
from TermTk import TTkDnDEvent
from TermTk import TTkTreeWidget, TTkTreeWidgetItem, TTkFileTreeWidgetItem
import TermTk as ttk
from TermTk.TTkWidgets.tabwidget import _TTkNewTabWidgetDragData
from .about import About
from .activitybar import TTKodeActivityBar
class TTKodeFileWidgetItem(TTkTreeWidgetItem):
class TTKodeFileWidgetItem(ttk.TTkTreeWidgetItem):
__slots__ = ('_path', '_lineNumber')
def __init__(self, *args, path:str, lineNumber:int=0, **kwargs) -> None:
self._path = path
@ -60,117 +42,181 @@ class TTKodeFileWidgetItem(TTkTreeWidgetItem):
def lineNumber(self) -> int:
return self._lineNumber
class _TextDocument(TextDocumentHighlight):
__slots__ = ('_filePath')
def __init__(self, filePath:str="", **kwargs):
self._filePath = filePath
class _TextDocument(ttk.TextDocumentHighlight):
__slots__ = ('_filePath', '_tabText',
'fileChangedStatus', '_changedStatus', '_savedSnapshot')
def __init__(self, filePath:str="", tabText:ttk.TTkString=ttk.TTkString(), **kwargs):
self.fileChangedStatus:ttk.pyTTkSignal = ttk.pyTTkSignal(bool, _TextDocument)
self._filePath:str = filePath
self._tabText = tabText
self._changedStatus:bool = False
super().__init__(**kwargs)
self._savedSnapshot = self.snapshootId()
self.guessLexerFromFilename(filePath)
self.contentsChanged.connect(self._handleContentChanged)
class TTKode(TTkGridLayout):
__slots__ = ('_kodeTab', '_documents', '_activityBar')
def __init__(self, *, files, **kwargs):
self._documents = {}
def getTabButtonStyle(self) -> dict:
if self._changedStatus:
return {'default':{'closeGlyph':''}}
else:
return {'default':{'closeGlyph':''}}
def _handleContentChanged(self) -> None:
'''A signal is emitted when the file status change, marking it as modified or not'''
# ttk.TTkLog.debug(f"{self.isUndoAvailable()=} == {self._changedStatus=}")
curState = self.changed() or self._savedSnapshot != self.snapshootId()
if self._changedStatus != curState:
self._changedStatus = not self._changedStatus
ttk.TTkLog.debug(f"{self.isUndoAvailable()=} == {self._changedStatus=}")
self.fileChangedStatus.emit(self._changedStatus, self)
def save(self):
self._changedStatus = False
self._savedSnapshot = self.snapshootId()
self.fileChangedStatus.emit(self._changedStatus, self)
pass
class _TextEdit(ttk.TTkTextEdit):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cursorPositionChanged.connect(self._positionChanged)
@ttk.pyTTkSlot(ttk.TTkTextCursor)
def _positionChanged(self, cursor:ttk.TTkTextCursor):
extra_selections = []
# Highlight Red only the lines under the cursor positions
cursor = self.textCursor().copy()
cursor.clearSelection()
selection = ttk.TTkTextEdit.ExtraSelection(
cursor=cursor,
color=ttk.TTkColor.bg("#333300"),
format=ttk.TTkK.SelectionFormat.FullWidthSelection)
extra_selections.append(selection)
self.setExtraSelections(extra_selections)
def goToLine(self, linenum: int) -> None:
w,h = self.size()
h = min(h, self.document().lineCount())
tedit:ttk.TTkTextEditView = self
tedit.textCursor().movePosition(operation=ttk.TTkTextCursor.MoveOperation.End)
tedit.ensureCursorVisible()
tedit.textCursor().setPosition(line=linenum-h//3,pos=0)
tedit.ensureCursorVisible()
tedit.textCursor().setPosition(line=linenum,pos=0)
class TTKode(ttk.TTkGridLayout):
__slots__ = ('_kodeTab', '_activityBar')
def __init__(self, **kwargs):
super().__init__(**kwargs)
appTemplate = TTkAppTemplate(border=False)
appTemplate = ttk.TTkAppTemplate(border=False)
self.addWidget(appTemplate)
self._kodeTab = TTkKodeTab(border=False, closable=True)
self._kodeTab = ttk.TTkKodeTab(border=False, barType=ttk.TTkBarType.NERD_1 ,closable=True)
self._kodeTab.setDropEventProxy(self._dropEventProxyFile)
appTemplate.setMenuBar(appMenuBar:=TTkMenuBarLayout(), TTkAppTemplate.MAIN)
appTemplate.setMenuBar(appMenuBar:=ttk.TTkMenuBarLayout(), ttk.TTkAppTemplate.MAIN)
fileMenu = appMenuBar.addMenu("&File")
fileMenu.addMenu("Open").menuButtonClicked.connect(self._showFileDialog)
fileMenu.addMenu("Close") # .menuButtonClicked.connect(self._closeFile)
fileMenu.addMenu("Exit").menuButtonClicked.connect(lambda _:TTkHelper.quit())
fileMenu.addMenu("Exit").menuButtonClicked.connect(lambda _:ttk.TTkHelper.quit())
def _showAbout(btn):
TTkHelper.overlay(None, About(), 30,10)
ttk.TTkHelper.overlay(None, About(), 30,10)
def _showAboutTTk(btn):
TTkHelper.overlay(None, TTkAbout(), 30,10)
ttk.TTkHelper.overlay(None, ttk.TTkAbout(), 30,10)
appMenuBar.addMenu("&Quit", alignment=TTkK.RIGHT_ALIGN).menuButtonClicked.connect(TTkHelper.quit)
helpMenu = appMenuBar.addMenu("&Help", alignment=TTkK.RIGHT_ALIGN)
appMenuBar.addMenu("&Quit", alignment=ttk.TTkK.RIGHT_ALIGN).menuButtonClicked.connect(ttk.TTkHelper.quit)
helpMenu = appMenuBar.addMenu("&Help", alignment=ttk.TTkK.RIGHT_ALIGN)
helpMenu.addMenu("About ...").menuButtonClicked.connect(_showAbout)
helpMenu.addMenu("About ttk").menuButtonClicked.connect(_showAboutTTk)
fileTree = TTkFileTree(path='.', dragDropMode=TTkK.DragDropMode.AllowDrag)
fileTree = ttk.TTkFileTree(path='.', dragDropMode=ttk.TTkK.DragDropMode.AllowDrag)
self._activityBar = TTKodeActivityBar()
self._activityBar.addActivity(name="Explorer", icon=TTkString("╔██\n╚═╝"), widget=fileTree, select=True)
self._activityBar.addActivity(name="Explorer", icon=ttk.TTkString("╔██\n╚═╝"), widget=fileTree, select=True)
appTemplate.setWidget(self._kodeTab, TTkAppTemplate.MAIN)
appTemplate.setItem(self._activityBar, TTkAppTemplate.LEFT, size=30)
appTemplate.setWidget(TTkLogViewer(), TTkAppTemplate.BOTTOM, title="Logs", size=3)
for file in files:
self._openFile(file)
appTemplate.setWidget(self._kodeTab, ttk.TTkAppTemplate.MAIN)
appTemplate.setItem(self._activityBar, ttk.TTkAppTemplate.LEFT, size=30)
appTemplate.setWidget(ttk.TTkLogViewer(), ttk.TTkAppTemplate.BOTTOM, title="Logs", size=3)
fileTree.fileActivated.connect(lambda x: self._openFile(x.path()))
pyTTkSlot()
self._kodeTab.tabAdded.connect(self._tabAdded)
def _getTabButtonFromWidget(self, widget:ttk.TTkWidget) -> ttk.TTkTabButton:
for item, tab in self._kodeTab.iterWidgets():
if item == widget:
return tab
return None
ttk.pyTTkSlot(ttk.TTkTabWidget, int)
def _tabAdded(self, tw:ttk.TTkTabWidget, index:int):
tb = tw.tabButton(index)
wid = tw.widget(index)
if isinstance(wid,_TextEdit):
tb.mergeStyle(wid.document().getTabButtonStyle())
ttk.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 = ttk.TTkFileDialogPicker(pos = (3,3), size=(75,24), caption="Pick Something", path=".", fileMode=ttk.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, lineNumber=0):
ttk.TTkHelper.overlay(None, filePicker, 20, 5, True)
def _getDocument(self, filePath) -> Tuple[_TextDocument, Optional[_TextEdit]]:
for item, _ in self._kodeTab.iterWidgets():
if issubclass(type(item), _TextEdit):
doc = item.document()
if issubclass(type(doc), _TextDocument):
if filePath == doc._filePath:
return doc, item
with open(filePath, 'r') as f:
content = f.read()
tabText = ttk.TTkString(ttk.TTkCfg.theme.fileIcon.getIcon(filePath),ttk.TTkCfg.theme.fileIconColor) + ttk.TTkColor.RST + " " + os.path.basename(filePath)
td = _TextDocument(text=content, filePath=filePath, tabText=tabText)
td.fileChangedStatus.connect(self._handleFileChangedStatus)
return td, None
ttk.pyTTkSlot(bool, _TextDocument)
def _handleFileChangedStatus(self, status:bool, doc:_TextDocument) -> None:
# ttk.TTkLog.debug(f"Status ({status}) -> {doc._filePath}")
for item, tab in self._kodeTab.iterWidgets():
if issubclass(type(item), _TextEdit):
if doc == item.document():
tab.mergeStyle(doc.getTabButtonStyle())
def _openFile(self, filePath, line:int=0, pos:int=0):
filePath = os.path.realpath(filePath)
if filePath in self._documents:
doc = self._documents[filePath]['doc']
doc, tedit = self._getDocument(filePath=filePath)
if tedit:
self._kodeTab.setCurrentWidget(tedit)
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)
if lineNumber:
tedit.textCursor().movePosition(operation=TTkTextCursor.MoveOperation.End)
tedit.ensureCursorVisible()
tedit.textCursor().setPosition(line=lineNumber,pos=0)
tedit.ensureCursorVisible()
newCursor = tedit.textCursor().copy()
newCursor.clearSelection()
selection = TTkTextEdit.ExtraSelection(
cursor=newCursor,
color=TTkColor.bg("#444400"),
format=TTkK.SelectionFormat.FullWidthSelection)
tedit.setExtraSelections([selection])
tedit = _TextEdit(document=doc, readOnly=False, lineNumber=True)
self._kodeTab.addTab(tedit, doc._tabText)
self._kodeTab.setCurrentWidget(tedit)
tedit.goToLine(line)
tedit.setFocus()
def _dropEventProxyFile(self, evt:TTkDnDEvent):
def _dropEventProxyFile(self, evt:ttk.TTkDnDEvent):
data = evt.data()
filePath = None
if ( issubclass(type(data), TTkTreeWidget._DropTreeData) and
data.items ):
if issubclass(type(data.items[0]), TTkFileTreeWidgetItem):
item:TTkFileTreeWidgetItem = data.items[0]
filePath = os.path.realpath(item.path())
if ( issubclass(type(data), ttk.TTkTreeWidget._DropTreeData) and data.items ):
if issubclass(type(data.items[0]), ttk.TTkFileTreeWidgetItem):
linenum:int = 0
ftwi:ttk.TTkFileTreeWidgetItem = data.items[0]
filePath = os.path.realpath(ftwi.path())
elif issubclass(type(data.items[0]), TTKodeFileWidgetItem):
item:TTkFileTreeWidgetItem = data.items[0]
filePath = os.path.realpath(item.path())
kfwi:TTKodeFileWidgetItem = data.items[0]
linenum:int = kfwi.lineNumber()
filePath = os.path.realpath(kfwi.path())
if 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)
doc, _ = self._getDocument(filePath=filePath)
tedit = _TextEdit(document=doc, readOnly=False, lineNumber=True)
tedit.goToLine(linenum)
newData = _TTkNewTabWidgetDragData(
widget=tedit,
label=label,
label=doc._tabText,
data=None,
closable=True
)
@ -178,6 +224,3 @@ class TTKode(TTkGridLayout):
newEvt.setData(newData)
return newEvt
return evt
# def _closeFile():
# if (index := KodeTab.lastUsed.currentIndex()) >= 0:
# KodeTab.lastUsed.removeTab(index)

35
apps/ttkode/ttkode/plugins/_010/findwidget.py

@ -100,7 +100,7 @@ def _walk_with_gitignore(root):
yield dirpath, filenames
class _ExpandButton(ttk.TTkButton):
class _ToggleButton(ttk.TTkButton):
def __init__(self, **kwargs):
params = {
'border':False,
@ -140,19 +140,26 @@ class FindWidget(ttk.TTkContainer):
super().__init__(**kwargs)
self.setLayout(layout:=ttk.TTkGridLayout())
searchLayout = ttk.TTkGridLayout()
searchLayout.addWidget(expandReplace:=_ExpandButton(), 0, 0)
searchLayout.addWidget(search :=ttk.TTkLineEdit(hint='Search'), 0, 1)
searchLayout.addWidget(expandReplace:=_ToggleButton(), 0, 0)
searchLayout.addWidget(search :=ttk.TTkLineEdit(hint='Search'), 0, 1)
searchLayout.addWidget(repl__l:=ttk.TTkLabel(visible=False, text='sub:'), 1, 0)
searchLayout.addWidget(ft_in_l:=ttk.TTkLabel(visible=False, text='inc:'), 2, 0)
searchLayout.addWidget(ft_ex_l:=ttk.TTkLabel(visible=False, text='exc:'), 3, 0)
searchLayout.addWidget(replace:=ttk.TTkLineEdit(visible=False, hint='Replace'), 1, 1)
searchLayout.addWidget(ft_incl:=ttk.TTkLineEdit(visible=False, hint='Files to include'), 2, 1)
searchLayout.addWidget(ft_excl:=ttk.TTkLineEdit(visible=False, hint='Files to exclude'), 3, 1)
layout.addItem(searchLayout, 0, 0)
layout.addWidget(btn_search:=ttk.TTkButton(text="Search", border=False), 4,0)
layout.addWidget(res_tree:=ttk.TTkTree(dragDropMode=ttk.TTkK.DragDropMode.AllowDrag), 5,0)
controlsLayout = ttk.TTkGridLayout()
controlsLayout.addWidget(btn_search:=ttk.TTkButton(text="Search", border=False), 0,0)
controlsLayout.addWidget(btn_replace:=ttk.TTkButton(text='Replace', border=False, enabled=False), 0, 1)
controlsLayout.addWidget(btn_expand :=ttk.TTkButton(text='+', maxWidth=3, border=False), 0, 2)
controlsLayout.addWidget(btn_collapse:=ttk.TTkButton(text='-', maxWidth=3, border=False), 0, 3)
layout.addItem(controlsLayout,1,0)
layout.addWidget(res_tree:=ttk.TTkTree(dragDropMode=ttk.TTkK.DragDropMode.AllowDrag), 2,0)
res_tree.setHeaderLabels(["Results"])
res_tree.setColumnWidth(0,100)
@ -170,15 +177,24 @@ class FindWidget(ttk.TTkContainer):
self._files_exc_le = ft_excl
btn_search.clicked.connect(self._search)
btn_expand.clicked.connect(self._results_tree.expandAll)
btn_collapse.clicked.connect(self._results_tree.collapseAll)
search.returnPressed.connect(self._search)
res_tree.itemActivated.connect(self._activated)
@ttk.pyTTkSlot(str)
def _replace_txt(value):
btn_replace.setEnabled(bool(value))
self._replace_le.textChanged.connect(_replace_txt)
@ttk.pyTTkSlot(ttk.TTkTreeWidgetItem, int)
def _activated(self, item:ttk.TTkTreeWidgetItem, _):
if isinstance(item, _MatchTreeWidgetItem):
file = item.path()
line = item.lineNumber()
ttkodeProxy.ttkode()._openFile(file, line)
ttkodeProxy.openFile(file, line)
@ttk.pyTTkSlot()
@ -197,10 +213,13 @@ class FindWidget(ttk.TTkContainer):
ttk.TTkString(
ttk.TTkCfg.theme.fileIcon.getIcon(file),
ttk.TTkCfg.theme.fileIconColor) + " " +
ttk.TTkString(f" {file} ", ttk.TTkColor.YELLOW+ttk.TTkColor.BOLD) +
ttk.TTkString(f" {file} ", ttk.TTkColor.YELLOW+ttk.TTkColor.BOLD+ttk.TTkColor.bg('#000088')) +
ttk.TTkString(f" {root} ", ttk.TTkColor.fg("#888888"))
],expanded=True)
for num,line in matches:
line = line.lstrip(' ')
# index = line.find(search_pattern)
# outLine =
item.addChild(
_MatchTreeWidgetItem([
ttk.TTkString(str(num)+" ",ttk.TTkColor.CYAN) +

15
apps/ttkode/ttkode/proxy.py

@ -22,6 +22,8 @@
__all__ = ['TTKodeViewerProxy', 'ttkodeProxy']
from typing import Optional, Callable, Any
import TermTk as ttk
from ttkode.app.ttkode import TTKode
@ -39,21 +41,26 @@ class TTKodeProxy():
'_ttkode',
# Signals
)
_ttkode:TTKode
_ttkode:Optional[TTKode]
_openFileCb:Optional[Callable[[Any, int, int], Any]]
def __init__(self) -> None:
self._openFileCb = lambda _ : None
self._openFileCb = None
self._ttkode = None
def setTTKode(self, ttkode:TTKode) -> None:
self._ttkode = ttkode
self._openFileCb = ttkode._openFile
def ttkode(self) -> TTKode:
if not self._ttkode:
raise Exception("TTkode uninitialized")
return self._ttkode
def setOpenFile(self, cb):
self._openFileCb = cb
def openFile(self, fileName):
return self._openFileCb(fileName)
def openFile(self, fileName:str, line:int=0, pos:int=0):
if self._ttkode and self._openFileCb:
return self._openFileCb(fileName, line, pos)
ttkodeProxy:TTKodeProxy = TTKodeProxy()
Loading…
Cancel
Save