I got a a piece of code which can highlight the syntax for Python Using Tkinter Text Widget. However, I still can't highlight the function name after 'def' and Class name after 'class' and the package name after 'import'. If something obvious is missing, please be gentle and convey the message to me.
python.yaml
categories:
keywords:
color: orange
matches: ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
variables:
color: red4
matches: ['True', 'False', None]
functions:
color: "#525fe9"
matches: ['abs',delattr','hash','memoryview','set','all','dict','help','min','setattr','any','dir','hex','next','slice','ascii','divmod','id','object','sorted','bin','enumerate','input','oct','staticmethod','bool','eval','int','open','str','breakpoint','exec','isinstance','ord','sum','bytearray','filter','issubclass','pow','super','bytes','float','iter','print','tuple','callable','format','len','property','type','chr','frozenset','list','range','vars','classmethod','getattr','locals','repr','zip','compile','globals','map','reversed','__import__','complex','hasattr','max',round']
numbers:
color: pink
strings:
color: "#e16d5b"
The highlighter.py helps to highlight words which it fetched from python.yaml file.
import tkinter as tk
import yaml
class Highlighter:
def __init__(self, text_widget, syntax_file):
self.text_widget = text_widget
self.syntax_file = syntax_file
self.categories = None
self.numbers_color = "blue"
self.disallowed_previous_chars = ["_", "-", "."]
self.parse_syntax_file()
self.text_widget.bind('<KeyRelease>', self.on_key_release)
def on_key_release(self, event=None):
self.highlight()
def parse_syntax_file(self):
with open(self.syntax_file, 'r') as stream:
config = yaml.safe_load(stream)
self.categories = config['categories']
self.numbers_color = config['numbers']['color']
self.strings_color = config['strings']['color']
self.configure_tags()
def callback_1(self,event):
info_window = tk.Tk()
info_window.overrideredirect(1)
info_window.geometry("200x24+{0}+{1}".format(event.x_root-100, event.y_root-12))
label = tk.Label(info_window, text="Word definition goes here.")
label.pack(fill=tk.BOTH)
info_window.bind_all("<Leave>", lambda e: info_window.destroy()) # Remove popup when pointer leaves the window
info_window.mainloop()
def configure_tags(self):
for category in self.categories.keys():
color = self.categories[category]['color']
self.text_widget.tag_configure(category, foreground=color)
self.text_widget.tag_configure("number", foreground=self.numbers_color)
self.text_widget.tag_configure("string", foreground=self.strings_color)
self.text_widget.tag_bind("string","<Enter>", self.callback_1)
def highlight(self, event=None):
length = tk.IntVar()
for category in self.categories:
matches = self.categories[category]['matches']
for keyword in matches:
start = 1.0
keyword = keyword + "[^A-Za-z_-]"
idx = self.text_widget.search(keyword, start, stopindex=tk.END, count=length, regexp=1)
while idx:
char_match_found = int(str(idx).split('.')[1])
line_match_found = int(str(idx).split('.')[0])
if char_match_found > 0:
previous_char_index = str(line_match_found) + '.' + str(char_match_found - 1)
previous_char = self.text_widget.get(previous_char_index, previous_char_index + "+1c")
if previous_char.isalnum() or previous_char in self.disallowed_previous_chars:
end = f"{idx}+{length.get() - 1}c"
start = end
idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1)
else:
end = f"{idx}+{length.get() - 1}c"
self.text_widget.tag_add(category, idx, end)
start = end
idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1)
else:
end = f"{idx}+{length.get() - 1}c"
self.text_widget.tag_add(category, idx, end)
start = end
idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1)
self.highlight_regex(r"(\d)+[.]?(\d)*", "number")
self.highlight_regex(r"[\'][^\']*[\']", "string")
self.highlight_regex(r"[\"][^\']*[\"]", "string")
def highlight_regex(self, regex, tag):
length = tk.IntVar()
start = 1.0
idx = self.text_widget.search(regex, start, stopindex=tk.END, regexp=1, count=length)
while idx:
end = f"{idx}+{length.get()}c"
self.text_widget.tag_add(tag, idx, end)
self.text_widget.tag_bind("string","<Enter>", self.callback_1)
start = end
idx = self.text_widget.search(regex, start, stopindex=tk.END, regexp=1, count=length)
if __name__ == '__main__':
w = tk.Tk()
x=tk.Text(w)
x.pack(fill=tk.BOTH,expand=1)
h = Highlighter(x, 'Path/to/python.yaml')
w.mainloop()