Skip to content

Commit ec10a06

Browse files
committed
use pygments syntax highlighter in BASIC editor
1 parent a0fa4ad commit ec10a06

File tree

5 files changed

+110
-83
lines changed

5 files changed

+110
-83
lines changed

README.creole

+1
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ Six is a Python 2 and 3 compatibility library.
395395
396396
== History
397397

398+
* 15.12.2014 - v0.3.2 - Use [[http://pygments.org/|Pygments]] syntax highlighter in BASIC editor
398399
* 08.10.2014 - Release as v0.3.1
399400
* 30.09.2014 - Enhance the BASIC editor
400401
* 29.09.2014 - Merge [[https://github.com/jedie/PyDragon32|PyDragon32]] project

basic_editor/editor.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def set_content(self, listing_ascii):
261261

262262
for line in listing_ascii:
263263
line = "%s\n" % line # use os.sep ?!?
264-
log.critical("\t%s", repr(line))
264+
log.debug("\t%s", repr(line))
265265
self.text.insert(tkinter.END, line)
266266
# self.text.config(state=Tkinter.DISABLED)
267267
self.text.mark_set(tkinter.INSERT, '1.0') # Set cursor at start

basic_editor/highlighting.py

+106-81
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212
"""
1313

1414
from __future__ import absolute_import, division, print_function
15+
16+
import pygments
17+
from pygments.styles import get_style_by_name
18+
1519
from basic_editor.tkinter_utils import TkTextTag
16-
from dragonlib.utils import six
17-
xrange = six.moves.xrange
20+
from dragonlib.dragon32.pygments_lexer import BasicLexer
21+
1822

1923
try:
2024
# python 3
@@ -30,6 +34,7 @@
3034
from dragonlib.core import basic_parser
3135

3236

37+
3338
class TkTextHighlighting(BaseExtension):
3439
"""
3540
code based on idlelib.ColorDelegator.ColorDelegator
@@ -40,101 +45,117 @@ class TkTextHighlighting(BaseExtension):
4045
def __init__(self, editor):
4146
super(TkTextHighlighting, self).__init__(editor)
4247

48+
self.lexer = BasicLexer()
49+
4350
self.machine_api = editor.machine_api
4451

45-
bold_font = font.Font(self.text, self.text.cget("font"))
46-
bold_font.configure(weight="bold")
47-
self.text.tag_configure("bold", font=bold_font)
52+
self.tags = self.create_tags()
53+
self.existing_tags = tuple(self.tags.values())
4854

49-
self.tagdefs = {
50-
self.TAG_LINE_NUMBER: {"foreground": "#333333", "background":"#f4f4f4"},
51-
self.TAG_JUMP_ADDESS: {"foreground":"#0000aa", "background":"#f4f4f4", "font":bold_font},
55+
# TODO: Add a bind callback list
56+
# see: http://www.python-forum.de/viewtopic.php?f=18&t=35275 (de)
57+
# self.editor.root.bind("<KeyRelease>", self.update)
58+
# self.editor.root.bind("<KeyRelease>", self.force_update)
5259

53-
basic_parser.CODE_TYPE_CODE: {"foreground":"#222222", "font":bold_font},
54-
basic_parser.CODE_TYPE_DATA: {"foreground":"#ddaaff", "font":bold_font},
55-
basic_parser.CODE_TYPE_STRING: {"foreground":"#0000ff"},# , "font":bold_font},
56-
basic_parser.CODE_TYPE_COMMENT: {"foreground":"#00aa00"},
57-
}
58-
for tag, args in list(self.tagdefs.items()):
59-
self.text.tag_configure(tag, **args)
60+
self.old_pos=None
61+
self.__update_interval()
6062

61-
# self.notify_range("1.0", "end")
63+
def __update_interval(self):
64+
""" highlight the current line """
65+
self.update()
66+
self.after_id = self.text.after(250, self.__update_interval)
6267

63-
self.old_pos = None
64-
self.__update_interval()
6568

66-
def update(self, force=False):
67-
pos = self.text.index(tkinter.INSERT)
69+
def force_update(self, event):
70+
print("force update")
71+
self.update(event, force=True)
6872

69-
if not force:
70-
if pos == self.old_pos:
71-
# log.critical("No recolorize needed.")
72-
return
73+
def update(self, event=None, force=False):
74+
pos = self.text.index(tkinter.INSERT)
75+
# print("update %s" % pos)
76+
if not force and pos == self.old_pos:
77+
# print("Skip")
78+
return
7379

7480
self.recolorize()
7581
self.old_pos = pos
7682

77-
def __update_interval(self):
78-
""" highlight the current line_no """
79-
self.update()
80-
self.after_id = self.text.after(10, self.__update_interval)
83+
# ---------------------------------------------------------------------------------------
84+
85+
def create_tags(self):
86+
tags={}
87+
88+
bold_font = font.Font(self.text, self.text.cget("font"))
89+
bold_font.configure(weight=font.BOLD)
90+
91+
italic_font = font.Font(self.text, self.text.cget("font"))
92+
italic_font.configure(slant=font.ITALIC)
93+
94+
bold_italic_font = font.Font(self.text, self.text.cget("font"))
95+
bold_italic_font.configure(weight=font.BOLD, slant=font.ITALIC)
96+
97+
style = get_style_by_name("default")
98+
for ttype, ndef in style:
99+
# print(ttype, ndef)
100+
tag_font = None
101+
if ndef["bold"] and ndef["italic"]:
102+
tag_font = bold_italic_font
103+
elif ndef["bold"]:
104+
tag_font = bold_font
105+
elif ndef["italic"]:
106+
tag_font = italic_font
107+
108+
if ndef["color"]:
109+
foreground = "#%s" % ndef["color"]
110+
else:
111+
foreground = None
81112

82-
# def notify_range(self, index1, index2=None):
83-
# self.text.tag_add("TODO", index1, index2)
113+
tags[ttype]=str(ttype)
114+
self.text.tag_configure(tags[ttype], foreground=foreground, font=tag_font)
115+
# self.text.tag_configure(str(ttype), foreground=foreground, font=tag_font)
84116

85-
def colorize(self, part_type, start, end):
86-
# print "colorize", part_type, start, end
87-
self.text.tag_add(part_type, start, end)
117+
return tags
88118

89119
def recolorize(self):
90-
self.removecolors()
120+
# print("recolorize")
121+
listing = self.text.get("1.0", "end-1c")
91122

92-
listing = self.editor.get_content()
93123
destinations = self.machine_api.renum_tool.get_destinations(listing)
94124

95-
line_max = self.text.index(tkinter.END).split('.')[0]
96-
line_max = int(line_max)
97-
for line_no in xrange(line_max):
98-
line_content = self.text.get("%s.0" % line_no, "%s.0+1lines" % line_no)
99-
# print "line:", repr(line_content)
100-
if not line_content.strip():
101-
continue
102-
103-
parsed_lines = self.machine_api.parse_ascii_listing(line_content)
104-
try:
105-
code_line_no, code_objects = list(parsed_lines.items())[0]
106-
except IndexError:
107-
continue
108-
# print "parsed line:", code_line_no, code_objects
109-
110-
index = len(str(code_line_no) + " ")
111-
112-
if code_line_no in destinations:
113-
# The current line number is used as a jump address
114-
part_type = self.TAG_JUMP_ADDESS
125+
tokensource = self.lexer.get_tokens(listing)
126+
127+
start_line=1
128+
start_index = 0
129+
end_line=1
130+
end_index = 0
131+
for ttype, value in tokensource:
132+
if "\n" in value:
133+
end_line += value.count("\n")
134+
end_index = len(value.rsplit("\n",1)[1])
115135
else:
116-
part_type = self.TAG_LINE_NUMBER
117-
self.colorize(part_type,
118-
start="%s.0" % line_no,
119-
end="%s.%s" % (line_no, index)
120-
)
136+
end_index += len(value)
137+
138+
if value not in (" ", "\n"):
139+
index1 = "%s.%s" % (start_line, start_index)
140+
index2 = "%s.%s" % (end_line, end_index)
141+
142+
for tagname in self.text.tag_names(index1): # FIXME
143+
# print("remove %s" % tagname)
144+
if tagname not in self.existing_tags: # Don"t remove e.g.: "current line"-tag
145+
# print("Skip...")
146+
continue
147+
self.text.tag_remove(tagname, index1, index2)
121148

122-
for code_object in code_objects:
123-
end = index + len(code_object.content)
124-
self.colorize(code_object.PART_TYPE,
125-
start="%s.%s" % (line_no, index),
126-
end="%s.%s" % (line_no, end),
127-
)
128-
index = end
149+
# Mark used line numbers extra:
150+
if start_index==0 and ttype==pygments.token.Name.Label:
151+
if int(value) in destinations:
152+
ttype = pygments.token.Name.Tag
129153

130-
# print
154+
self.text.tag_add(self.tags[ttype], index1, index2)
131155

132-
# line, column = self.text.index(Tkinter.INSERT).split('.')
133-
# print "recolorize lines %s" % line
156+
start_line = end_line
157+
start_index = end_index
134158

135-
def removecolors(self):
136-
for tag in self.tagdefs:
137-
self.text.tag_remove(tag, "1.0", "end")
138159

139160

140161

@@ -147,28 +168,32 @@ def __init__(self, editor):
147168

148169
self.tag_current_line = TkTextTag(self.text,
149170
background="#e8f2fe"
150-
# relief='raised', borderwidth=1,
171+
# relief="raised", borderwidth=1,
151172
)
152173

153174
self.current_line = None
154175
self.__update_interval()
155176

156-
def update(self, force=False):
177+
# self.editor.root.bind("<KeyRelease>", self.update)
178+
179+
def update(self, event=None, force=False):
157180
""" highlight the current line """
158-
line_no = self.text.index(tkinter.INSERT).split('.')[0]
181+
line_no = self.text.index(tkinter.INSERT).split(".")[0]
159182

160-
if not force:
161-
if line_no == self.current_line:
183+
# if not force:
184+
# if line_no == self.current_line:
162185
# log.critical("no highlight line needed.")
163-
return
186+
# return
164187

165188
# log.critical("highlight line: %s" % line_no)
166-
self.current_line = line_no
189+
# self.current_line = line_no
167190

168191
self.text.tag_remove(self.tag_current_line.id, "1.0", "end")
169192
self.text.tag_add(self.tag_current_line.id, "%s.0" % line_no, "%s.0+1lines" % line_no)
170193

171194
def __update_interval(self):
172195
""" highlight the current line """
173196
self.update()
174-
self.after_id = self.text.after(10, self.__update_interval)
197+
self.after_id = self.text.after(250, self.__update_interval)
198+
199+

dragonpy/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.3.1"
1+
__version__ = "0.3.2"

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
provides=["DragonPy"],
4141
install_requires=[
4242
"dragonlib",
43+
"pygments",
4344
],
4445
author="Jens Diemer",
4546
author_email="[email protected]",

0 commit comments

Comments
 (0)