1111CHECK_DELAY = 100 # milliseconds
1212
1313class ParenMatch :
14- """Highlight matching parentheses
14+ """Highlight matching openers and closers, (), [], and {}.
1515
16- There are three supported style of paren matching, based loosely
17- on the Emacs options. The style is select based on the
18- HILITE_STYLE attribute; it can be changed used the set_style
19- method.
16+ There are three supported styles of paren matching. When a right
17+ paren (opener) is typed:
2018
21- The supported styles are:
19+ opener -- highlight the matching left paren (closer);
20+ parens -- highlight the left and right parens (opener and closer);
21+ expression -- highlight the entire expression from opener to closer.
22+ (For back compatibility, 'default' is a synonym for 'opener').
2223
23- default -- When a right paren is typed, highlight the matching
24- left paren for 1/2 sec.
25-
26- expression -- When a right paren is typed, highlight the entire
27- expression from the left paren to the right paren.
24+ Flash-delay is the maximum milliseconds the highlighting remains.
25+ Any cursor movement (key press or click) before that removes the
26+ highlight. If flash-delay is 0, there is no maximum.
2827
2928 TODO:
30- - extend IDLE with configuration dialog to change options
31- - implement rest of Emacs highlight styles (see below)
32- - print mismatch warning in IDLE status window
33-
34- Note: In Emacs, there are several styles of highlight where the
35- matching paren is highlighted whenever the cursor is immediately
36- to the right of a right paren. I don't know how to do that in Tk,
37- so I haven't bothered.
29+ - Augment bell() with mismatch warning in status window.
30+ - Highlight when cursor is moved to the right of a closer.
31+ This might be too expensive to check.
3832 """
3933 menudefs = [
4034 ('edit' , [
4135 ("Show surrounding parens" , "<<flash-paren>>" ),
4236 ])
4337 ]
44- STYLE = idleConf .GetOption ('extensions' ,'ParenMatch' ,'style' ,
45- default = 'expression' )
46- FLASH_DELAY = idleConf .GetOption ('extensions' ,'ParenMatch' ,'flash-delay' ,
47- type = 'int' ,default = 500 )
38+ STYLE = idleConf .GetOption (
39+ 'extensions' ,'ParenMatch' ,'style' , default = 'expression' )
40+ FLASH_DELAY = idleConf .GetOption (
41+ 'extensions' ,'ParenMatch' ,'flash-delay' , type = 'int' ,default = 500 )
42+ BELL = idleConf .GetOption (
43+ 'extensions' ,'ParenMatch' ,'bell' , type = 'bool' ,default = 1 )
4844 HILITE_CONFIG = idleConf .GetHighlight (idleConf .CurrentTheme (),'hilite' )
49- BELL = idleConf .GetOption ('extensions' ,'ParenMatch' ,'bell' ,
50- type = 'bool' ,default = 1 )
5145
5246 RESTORE_VIRTUAL_EVENT_NAME = "<<parenmatch-check-restore>>"
5347 # We want the restore event be called before the usual return and
@@ -69,39 +63,45 @@ def __init__(self, editwin):
6963 self .set_style (self .STYLE )
7064
7165 def activate_restore (self ):
66+ "Activate mechanism to restore text from highlighting."
7267 if not self .is_restore_active :
7368 for seq in self .RESTORE_SEQUENCES :
7469 self .text .event_add (self .RESTORE_VIRTUAL_EVENT_NAME , seq )
7570 self .is_restore_active = True
7671
7772 def deactivate_restore (self ):
73+ "Remove restore event bindings."
7874 if self .is_restore_active :
7975 for seq in self .RESTORE_SEQUENCES :
8076 self .text .event_delete (self .RESTORE_VIRTUAL_EVENT_NAME , seq )
8177 self .is_restore_active = False
8278
8379 def set_style (self , style ):
80+ "Set tag and timeout functions."
8481 self .STYLE = style
85- if style == "default" :
86- self .create_tag = self .create_tag_default
87- self .set_timeout = self .set_timeout_last
88- elif style == "expression" :
89- self .create_tag = self .create_tag_expression
90- self .set_timeout = self .set_timeout_none
82+ self .create_tag = (
83+ self .create_tag_opener if style in {"opener" , "default" } else
84+ self .create_tag_parens if style == "parens" else
85+ self .create_tag_expression ) # "expression" or unknown
86+
87+ self .set_timeout = (self .set_timeout_last if self .FLASH_DELAY else
88+ self .set_timeout_none )
9189
9290 def flash_paren_event (self , event ):
91+ "Handle editor 'show surrounding parens' event (menu or shortcut)."
9392 indices = (HyperParser (self .editwin , "insert" )
9493 .get_surrounding_brackets ())
9594 if indices is None :
9695 self .bell ()
9796 return "break"
9897 self .activate_restore ()
9998 self .create_tag (indices )
100- self .set_timeout_last ()
99+ self .set_timeout ()
101100 return "break"
102101
103102 def paren_closed_event (self , event ):
104- # If it was a shortcut and not really a closing paren, quit.
103+ "Handle user input of closer."
104+ # If user bound non-closer to <<paren-closed>>, quit.
105105 closer = self .text .get ("insert-1c" )
106106 if closer not in _openers :
107107 return "break"
@@ -118,6 +118,7 @@ def paren_closed_event(self, event):
118118 return "break"
119119
120120 def restore_event (self , event = None ):
121+ "Remove effect of doing match."
121122 self .text .tag_delete ("paren" )
122123 self .deactivate_restore ()
123124 self .counter += 1 # disable the last timer, if there is one.
@@ -129,11 +130,20 @@ def handle_restore_timer(self, timer_count):
129130 # any one of the create_tag_XXX methods can be used depending on
130131 # the style
131132
132- def create_tag_default (self , indices ):
133+ def create_tag_opener (self , indices ):
133134 """Highlight the single paren that matches"""
134135 self .text .tag_add ("paren" , indices [0 ])
135136 self .text .tag_config ("paren" , self .HILITE_CONFIG )
136137
138+ def create_tag_parens (self , indices ):
139+ """Highlight the left and right parens"""
140+ if self .text .get (indices [1 ]) in (')' , ']' , '}' ):
141+ rightindex = indices [1 ]+ "+1c"
142+ else :
143+ rightindex = indices [1 ]
144+ self .text .tag_add ("paren" , indices [0 ], indices [0 ]+ "+1c" , rightindex + "-1c" , rightindex )
145+ self .text .tag_config ("paren" , self .HILITE_CONFIG )
146+
137147 def create_tag_expression (self , indices ):
138148 """Highlight the entire expression"""
139149 if self .text .get (indices [1 ]) in (')' , ']' , '}' ):
@@ -162,7 +172,7 @@ def callme(callme, self=self, c=self.counter,
162172 self .editwin .text_frame .after (CHECK_DELAY , callme , callme )
163173
164174 def set_timeout_last (self ):
165- """The last highlight created will be removed after .5 sec """
175+ """The last highlight created will be removed after FLASH_DELAY millisecs """
166176 # associate a counter with an event; only disable the "paren"
167177 # tag if the event is for the most recent timer.
168178 self .counter += 1
0 commit comments