12
12
"""
13
13
14
14
from __future__ import absolute_import , division , print_function
15
+
16
+ import pygments
17
+ from pygments .styles import get_style_by_name
18
+
15
19
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
+
18
22
19
23
try :
20
24
# python 3
30
34
from dragonlib .core import basic_parser
31
35
32
36
37
+
33
38
class TkTextHighlighting (BaseExtension ):
34
39
"""
35
40
code based on idlelib.ColorDelegator.ColorDelegator
@@ -40,101 +45,117 @@ class TkTextHighlighting(BaseExtension):
40
45
def __init__ (self , editor ):
41
46
super (TkTextHighlighting , self ).__init__ (editor )
42
47
48
+ self .lexer = BasicLexer ()
49
+
43
50
self .machine_api = editor .machine_api
44
51
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 ())
48
54
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)
52
59
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 ()
60
62
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 )
62
67
63
- self .old_pos = None
64
- self .__update_interval ()
65
68
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 )
68
72
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
73
79
74
80
self .recolorize ()
75
81
self .old_pos = pos
76
82
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
81
112
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)
84
116
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
88
118
89
119
def recolorize (self ):
90
- self .removecolors ()
120
+ # print("recolorize")
121
+ listing = self .text .get ("1.0" , "end-1c" )
91
122
92
- listing = self .editor .get_content ()
93
123
destinations = self .machine_api .renum_tool .get_destinations (listing )
94
124
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 ])
115
135
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 )
121
148
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
129
153
130
- # print
154
+ self . text . tag_add ( self . tags [ ttype ], index1 , index2 )
131
155
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
134
158
135
- def removecolors (self ):
136
- for tag in self .tagdefs :
137
- self .text .tag_remove (tag , "1.0" , "end" )
138
159
139
160
140
161
@@ -147,28 +168,32 @@ def __init__(self, editor):
147
168
148
169
self .tag_current_line = TkTextTag (self .text ,
149
170
background = "#e8f2fe"
150
- # relief=' raised' , borderwidth=1,
171
+ # relief=" raised" , borderwidth=1,
151
172
)
152
173
153
174
self .current_line = None
154
175
self .__update_interval ()
155
176
156
- def update (self , force = False ):
177
+ # self.editor.root.bind("<KeyRelease>", self.update)
178
+
179
+ def update (self , event = None , force = False ):
157
180
""" highlight the current line """
158
- line_no = self .text .index (tkinter .INSERT ).split ('.' )[0 ]
181
+ line_no = self .text .index (tkinter .INSERT ).split ("." )[0 ]
159
182
160
- if not force :
161
- if line_no == self .current_line :
183
+ # if not force:
184
+ # if line_no == self.current_line:
162
185
# log.critical("no highlight line needed.")
163
- return
186
+ # return
164
187
165
188
# log.critical("highlight line: %s" % line_no)
166
- self .current_line = line_no
189
+ # self.current_line = line_no
167
190
168
191
self .text .tag_remove (self .tag_current_line .id , "1.0" , "end" )
169
192
self .text .tag_add (self .tag_current_line .id , "%s.0" % line_no , "%s.0+1lines" % line_no )
170
193
171
194
def __update_interval (self ):
172
195
""" highlight the current line """
173
196
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
+
0 commit comments