11
11
CHECK_DELAY = 100 # milliseconds
12
12
13
13
class ParenMatch :
14
- """Highlight matching parentheses
14
+ """Highlight matching openers and closers, (), [], and {}.
15
15
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:
20
18
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').
22
23
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.
28
27
29
28
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.
38
32
"""
39
33
menudefs = [
40
34
('edit' , [
41
35
("Show surrounding parens" , "<<flash-paren>>" ),
42
36
])
43
37
]
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 )
48
44
HILITE_CONFIG = idleConf .GetHighlight (idleConf .CurrentTheme (),'hilite' )
49
- BELL = idleConf .GetOption ('extensions' ,'ParenMatch' ,'bell' ,
50
- type = 'bool' ,default = 1 )
51
45
52
46
RESTORE_VIRTUAL_EVENT_NAME = "<<parenmatch-check-restore>>"
53
47
# We want the restore event be called before the usual return and
@@ -69,39 +63,45 @@ def __init__(self, editwin):
69
63
self .set_style (self .STYLE )
70
64
71
65
def activate_restore (self ):
66
+ "Activate mechanism to restore text from highlighting."
72
67
if not self .is_restore_active :
73
68
for seq in self .RESTORE_SEQUENCES :
74
69
self .text .event_add (self .RESTORE_VIRTUAL_EVENT_NAME , seq )
75
70
self .is_restore_active = True
76
71
77
72
def deactivate_restore (self ):
73
+ "Remove restore event bindings."
78
74
if self .is_restore_active :
79
75
for seq in self .RESTORE_SEQUENCES :
80
76
self .text .event_delete (self .RESTORE_VIRTUAL_EVENT_NAME , seq )
81
77
self .is_restore_active = False
82
78
83
79
def set_style (self , style ):
80
+ "Set tag and timeout functions."
84
81
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 )
91
89
92
90
def flash_paren_event (self , event ):
91
+ "Handle editor 'show surrounding parens' event (menu or shortcut)."
93
92
indices = (HyperParser (self .editwin , "insert" )
94
93
.get_surrounding_brackets ())
95
94
if indices is None :
96
95
self .bell ()
97
96
return "break"
98
97
self .activate_restore ()
99
98
self .create_tag (indices )
100
- self .set_timeout_last ()
99
+ self .set_timeout ()
101
100
return "break"
102
101
103
102
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.
105
105
closer = self .text .get ("insert-1c" )
106
106
if closer not in _openers :
107
107
return "break"
@@ -118,6 +118,7 @@ def paren_closed_event(self, event):
118
118
return "break"
119
119
120
120
def restore_event (self , event = None ):
121
+ "Remove effect of doing match."
121
122
self .text .tag_delete ("paren" )
122
123
self .deactivate_restore ()
123
124
self .counter += 1 # disable the last timer, if there is one.
@@ -129,11 +130,20 @@ def handle_restore_timer(self, timer_count):
129
130
# any one of the create_tag_XXX methods can be used depending on
130
131
# the style
131
132
132
- def create_tag_default (self , indices ):
133
+ def create_tag_opener (self , indices ):
133
134
"""Highlight the single paren that matches"""
134
135
self .text .tag_add ("paren" , indices [0 ])
135
136
self .text .tag_config ("paren" , self .HILITE_CONFIG )
136
137
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
+
137
147
def create_tag_expression (self , indices ):
138
148
"""Highlight the entire expression"""
139
149
if self .text .get (indices [1 ]) in (')' , ']' , '}' ):
@@ -162,7 +172,7 @@ def callme(callme, self=self, c=self.counter,
162
172
self .editwin .text_frame .after (CHECK_DELAY , callme , callme )
163
173
164
174
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 """
166
176
# associate a counter with an event; only disable the "paren"
167
177
# tag if the event is for the most recent timer.
168
178
self .counter += 1
0 commit comments