8
8
import string
9
9
import sys
10
10
11
- # These constants represent the two different types of completions.
12
- # They must be defined here so autocomple_w can import them.
13
- COMPLETE_ATTRIBUTES , COMPLETE_FILES = range (1 , 2 + 1 )
14
-
11
+ # Two types of completions; defined here for autocomplete_w import below.
12
+ ATTRS , FILES = 0 , 1
15
13
from idlelib import autocomplete_w
16
14
from idlelib .config import idleConf
17
15
from idlelib .hyperparser import HyperParser
18
16
17
+ # Tuples passed to open_completions.
18
+ # EvalFunc, Complete, WantWin, Mode
19
+ FORCE = True , False , True , None # Control-Space.
20
+ TAB = False , True , True , None # Tab.
21
+ TRY_A = False , False , False , ATTRS # '.' for attributes.
22
+ TRY_F = False , False , False , FILES # '/' in quotes for file name.
23
+
19
24
# This string includes all chars that may be in an identifier.
20
25
# TODO Update this here and elsewhere.
21
26
ID_CHARS = string .ascii_letters + string .digits + "_"
22
27
23
- SEPS = os .sep
24
- if os .altsep : # e.g. '/' on Windows...
25
- SEPS += os .altsep
26
-
28
+ SEPS = f"{ os .sep } { os .altsep if os .altsep else '' } "
29
+ TRIGGERS = f".{ SEPS } "
27
30
28
31
class AutoComplete :
29
32
30
33
def __init__ (self , editwin = None ):
31
34
self .editwin = editwin
32
- if editwin is not None : # not in subprocess or test
35
+ if editwin is not None : # not in subprocess or no-gui test
33
36
self .text = editwin .text
34
- self .autocompletewindow = None
35
- # id of delayed call, and the index of the text insert when
36
- # the delayed call was issued. If _delayed_completion_id is
37
- # None, there is no delayed call.
38
- self ._delayed_completion_id = None
39
- self ._delayed_completion_index = None
37
+ self .autocompletewindow = None
38
+ # id of delayed call, and the index of the text insert when
39
+ # the delayed call was issued. If _delayed_completion_id is
40
+ # None, there is no delayed call.
41
+ self ._delayed_completion_id = None
42
+ self ._delayed_completion_index = None
40
43
41
44
@classmethod
42
45
def reload (cls ):
43
46
cls .popupwait = idleConf .GetOption (
44
47
"extensions" , "AutoComplete" , "popupwait" , type = "int" , default = 0 )
45
48
46
- def _make_autocomplete_window (self ):
49
+ def _make_autocomplete_window (self ): # Makes mocking easier.
47
50
return autocomplete_w .AutoCompleteWindow (self .text )
48
51
49
52
def _remove_autocomplete_window (self , event = None ):
@@ -52,30 +55,12 @@ def _remove_autocomplete_window(self, event=None):
52
55
self .autocompletewindow = None
53
56
54
57
def force_open_completions_event (self , event ):
55
- """Happens when the user really wants to open a completion list, even
56
- if a function call is needed.
57
- """
58
- self .open_completions (True , False , True )
58
+ "(^space) Open completion list, even if a function call is needed."
59
+ self .open_completions (FORCE )
59
60
return "break"
60
61
61
- def try_open_completions_event (self , event ):
62
- """Happens when it would be nice to open a completion list, but not
63
- really necessary, for example after a dot, so function
64
- calls won't be made.
65
- """
66
- lastchar = self .text .get ("insert-1c" )
67
- if lastchar == "." :
68
- self ._open_completions_later (False , False , False ,
69
- COMPLETE_ATTRIBUTES )
70
- elif lastchar in SEPS :
71
- self ._open_completions_later (False , False , False ,
72
- COMPLETE_FILES )
73
-
74
62
def autocomplete_event (self , event ):
75
- """Happens when the user wants to complete his word, and if necessary,
76
- open a completion list after that (if there is more than one
77
- completion)
78
- """
63
+ "(tab) Complete word or open list if multiple options."
79
64
if hasattr (event , "mc_state" ) and event .mc_state or \
80
65
not self .text .get ("insert linestart" , "insert" ).strip ():
81
66
# A modifier was pressed along with the tab or
@@ -85,34 +70,34 @@ def autocomplete_event(self, event):
85
70
self .autocompletewindow .complete ()
86
71
return "break"
87
72
else :
88
- opened = self .open_completions (False , True , True )
73
+ opened = self .open_completions (TAB )
89
74
return "break" if opened else None
90
75
91
- def _open_completions_later (self , * args ):
92
- self ._delayed_completion_index = self .text .index ("insert" )
93
- if self ._delayed_completion_id is not None :
94
- self .text .after_cancel (self ._delayed_completion_id )
95
- self ._delayed_completion_id = \
96
- self .text .after (self .popupwait , self ._delayed_open_completions ,
97
- * args )
98
-
99
- def _delayed_open_completions (self , * args ):
76
+ def try_open_completions_event (self , event = None ):
77
+ "(./) Open completion list after pause with no movement."
78
+ lastchar = self .text .get ("insert-1c" )
79
+ if lastchar in TRIGGERS :
80
+ args = TRY_A if lastchar == "." else TRY_F
81
+ self ._delayed_completion_index = self .text .index ("insert" )
82
+ if self ._delayed_completion_id is not None :
83
+ self .text .after_cancel (self ._delayed_completion_id )
84
+ self ._delayed_completion_id = self .text .after (
85
+ self .popupwait , self ._delayed_open_completions , args )
86
+
87
+ def _delayed_open_completions (self , args ):
88
+ "Call open_completions if index unchanged."
100
89
self ._delayed_completion_id = None
101
90
if self .text .index ("insert" ) == self ._delayed_completion_index :
102
- self .open_completions (* args )
91
+ self .open_completions (args )
103
92
104
- def open_completions (self , evalfuncs , complete , userWantsWin , mode = None ):
93
+ def open_completions (self , args ):
105
94
"""Find the completions and create the AutoCompleteWindow.
106
95
Return True if successful (no syntax error or so found).
107
96
If complete is True, then if there's nothing to complete and no
108
97
start of completion, won't open completions and return False.
109
98
If mode is given, will open a completion list only in this mode.
110
-
111
- Action Function Eval Complete WantWin Mode
112
- ^space force_open_completions True, False, True no
113
- . or / try_open_completions False, False, False yes
114
- tab autocomplete False, True, True no
115
99
"""
100
+ evalfuncs , complete , wantwin , mode = args
116
101
# Cancel another delayed call, if it exists.
117
102
if self ._delayed_completion_id is not None :
118
103
self .text .after_cancel (self ._delayed_completion_id )
@@ -121,14 +106,14 @@ def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
121
106
hp = HyperParser (self .editwin , "insert" )
122
107
curline = self .text .get ("insert linestart" , "insert" )
123
108
i = j = len (curline )
124
- if hp .is_in_string () and (not mode or mode == COMPLETE_FILES ):
109
+ if hp .is_in_string () and (not mode or mode == FILES ):
125
110
# Find the beginning of the string.
126
111
# fetch_completions will look at the file system to determine
127
112
# whether the string value constitutes an actual file name
128
113
# XXX could consider raw strings here and unescape the string
129
114
# value if it's not raw.
130
115
self ._remove_autocomplete_window ()
131
- mode = COMPLETE_FILES
116
+ mode = FILES
132
117
# Find last separator or string start
133
118
while i and curline [i - 1 ] not in "'\" " + SEPS :
134
119
i -= 1
@@ -138,17 +123,17 @@ def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
138
123
while i and curline [i - 1 ] not in "'\" " :
139
124
i -= 1
140
125
comp_what = curline [i :j ]
141
- elif hp .is_in_code () and (not mode or mode == COMPLETE_ATTRIBUTES ):
126
+ elif hp .is_in_code () and (not mode or mode == ATTRS ):
142
127
self ._remove_autocomplete_window ()
143
- mode = COMPLETE_ATTRIBUTES
128
+ mode = ATTRS
144
129
while i and (curline [i - 1 ] in ID_CHARS or ord (curline [i - 1 ]) > 127 ):
145
130
i -= 1
146
131
comp_start = curline [i :j ]
147
- if i and curline [i - 1 ] == '.' :
132
+ if i and curline [i - 1 ] == '.' : # Need object with attributes.
148
133
hp .set_index ("insert-%dc" % (len (curline )- (i - 1 )))
149
134
comp_what = hp .get_expression ()
150
- if not comp_what or \
151
- (not evalfuncs and comp_what .find ('(' ) != - 1 ):
135
+ if ( not comp_what or
136
+ (not evalfuncs and comp_what .find ('(' ) != - 1 )) :
152
137
return None
153
138
else :
154
139
comp_what = ""
@@ -163,7 +148,7 @@ def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
163
148
self .autocompletewindow = self ._make_autocomplete_window ()
164
149
return not self .autocompletewindow .show_window (
165
150
comp_lists , "insert-%dc" % len (comp_start ),
166
- complete , mode , userWantsWin )
151
+ complete , mode , wantwin )
167
152
168
153
def fetch_completions (self , what , mode ):
169
154
"""Return a pair of lists of completions for something. The first list
@@ -185,7 +170,7 @@ def fetch_completions(self, what, mode):
185
170
return rpcclt .remotecall ("exec" , "get_the_completion_list" ,
186
171
(what , mode ), {})
187
172
else :
188
- if mode == COMPLETE_ATTRIBUTES :
173
+ if mode == ATTRS :
189
174
if what == "" :
190
175
namespace = {** __main__ .__builtins__ .__dict__ ,
191
176
** __main__ .__dict__ }
@@ -207,7 +192,7 @@ def fetch_completions(self, what, mode):
207
192
except :
208
193
return [], []
209
194
210
- elif mode == COMPLETE_FILES :
195
+ elif mode == FILES :
211
196
if what == "" :
212
197
what = "."
213
198
try :
0 commit comments