Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
import customMenuItem
from objc_util import *
class findInSourcesMenu(customMenuItem.PYUIMenuItem):
__selector__ = 'findInSourcesMenu'
__title__ = 'Find'
def action(self, selected_text, selection, editorview):
import console
import os
import ui
search_term = selected_text
if search_term == '': # no text selected
# ask it
search_term = console.input_alert('text to search in sources', '', '')
if search_term == '': # no text entered
return # no action
tv = ui.TableView()
tv.search_term = search_term
sources = []
path = os.path.expanduser('~/Documents')
se = search_term.lower()
# search all .py. Tests show that os.scandir is quicker than os.walk
def scantree(path):
"""Recursively yield DirEntry objects for given directory."""
for entry in os.scandir(path):
if entry.is_dir(follow_symlinks=False):
fpath = entry.path
if os.path.splitext(entry.path)[-1].lower() != ".py":
with open(fpath, mode='rt', encoding='utf-8', errors='ignore') as fil:
content =
if se in content:
def tableview_cell_for_row(tableview, section, row):
cell = ui.TableViewCell()
data = tableview.data_source.items[row]
tx = '/Pythonista3/Documents/'
i = data.find(tx) + len(tx)
cell.text_label.text = data[i:]
return cell
class MyTableViewDelegate (object):
def tableview_did_select(self,tableview, section, row):
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
from pygments.styles import get_style_by_name
import re
import ui
from wkwebview import WKWebView
fpath = tableview.data_source.items[row]
search_term = tableview.search_term
with open(fpath, mode='rt', encoding='utf-8', errors='ignore') as fil:
code =
# Syntax-highlight code
# from omz code at
html_formatter = HtmlFormatter(style='colorful')
l = PythonLexer()
l.add_filter('whitespace', tabs=' ', tabsize=2)
highlighted_code = highlight(code, l, html_formatter)
styles = html_formatter.get_style_defs()
# change html code to highlight searched term with yellow background
styles = styles + '\n' + '.search { background-color: #ffff00 } /* search term */'
highlighted_code = highlighted_code.replace(search_term, '</span><span class="search">' + search_term + '</span>')
# add class to searched term independantly of case
src_str = re.compile('('+search_term+')', re.IGNORECASE)
# @Olaf: use \1 to refer to matched text grouped by () in the regex
highlighted_code = src_str.sub(r'</span><span class="search">\1</span>', highlighted_code)
# meta tag UTF-8 is needed to display emojis if present in a script
html = '<html><head><meta charset="UTF-8"><style>%s</style></head><body> %s </body></html>' % (styles, highlighted_code)
wv = WKWebView()
tx = '/Pythonista3/Documents/'
i = fpath.find(tx) + len(tx) = fpath[i:]
wv.frame = tableview.frame
tv.data_source = ui.ListDataSource(items=sources)
tv.delegate = MyTableViewDelegate()
tv.data_source.tableview_cell_for_row = tableview_cell_for_row
bs1 = ui.ButtonItem(title='search',tint_color='black')
bs2 = ui.ButtonItem(title=search_term,tint_color='green')
bs3 = ui.ButtonItem(title='in my scripts',tint_color='black')
tv.right_button_items = [bs3,bs2,bs1]
g = customMenuItem.MenuNotificationObserver([(findInSourcesMenu(),'Help')])
Copy link

jsbain commented Apr 10, 2020

Heres an idea... kick off a background thread in the menuitem action that does the recusive search.
When you append, call TableView.insert_rows(rows). the item selected callback would need to set a flag to stop the search.
This would allow results to populate in realtime.

Copy link

jsbain commented Apr 10, 2020

this may also require a modified data source, since the default might be calling reload

Copy link

cvpe commented Apr 10, 2020

Thanks for your, as usual very appreciated, advices, I promise I'll do it, but please, let me some time. My wife asks me to work in the garden 😢😪

Copy link

cvpe commented Apr 12, 2020

I'll not stop the scan background thread even if we select a file to watch because if we come back to watch another file, the list has still increased and should be normally ended. But I'll stop the thread if we close the TableView.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment