blob: e20b757d871043942e32eb06d1365c5b48404646 [file] [log] [blame]
wohlganger58fc71c2017-09-10 16:19:47 -05001"""Complete either attribute names or file names.
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00002
wohlganger58fc71c2017-09-10 16:19:47 -05003Either on demand or after a user-selected delay after a key character,
4pop up a list of candidates.
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00005"""
Terry Jan Reedy0fe45132019-03-24 17:12:28 -04006import __main__
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00007import os
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00008import string
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04009import sys
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000010
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040011# These constants represent the two different types of completions.
12# They must be defined here so autocomple_w can import them.
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000013COMPLETE_ATTRIBUTES, COMPLETE_FILES = range(1, 2+1)
14
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040015from idlelib import autocomplete_w
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040016from idlelib.config import idleConf
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040017from idlelib.hyperparser import HyperParser
Kurt B. Kaisere1b4a162007-08-10 02:45:06 +000018
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040019# This string includes all chars that may be in an identifier.
20# TODO Update this here and elsewhere.
21ID_CHARS = string.ascii_letters + string.digits + "_"
22
Christian Heimes81ee3ef2008-05-04 22:42:01 +000023SEPS = os.sep
24if os.altsep: # e.g. '/' on Windows...
25 SEPS += os.altsep
26
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040027
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000028class AutoComplete:
29
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000030 def __init__(self, editwin=None):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000031 self.editwin = editwin
wohlganger58fc71c2017-09-10 16:19:47 -050032 if editwin is not None: # not in subprocess or test
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -040033 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
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000040
wohlganger58fc71c2017-09-10 16:19:47 -050041 @classmethod
42 def reload(cls):
43 cls.popupwait = idleConf.GetOption(
44 "extensions", "AutoComplete", "popupwait", type="int", default=0)
45
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000046 def _make_autocomplete_window(self):
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040047 return autocomplete_w.AutoCompleteWindow(self.text)
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000048
49 def _remove_autocomplete_window(self, event=None):
50 if self.autocompletewindow:
51 self.autocompletewindow.hide_window()
52 self.autocompletewindow = None
53
54 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)
Serhiy Storchaka213ce122017-06-27 07:02:32 +030059 return "break"
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000060
61 def try_open_completions_event(self, event):
62 """Happens when it would be nice to open a completion list, but not
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +030063 really necessary, for example after a dot, so function
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000064 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)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000070 elif lastchar in SEPS:
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000071 self._open_completions_later(False, False, False,
72 COMPLETE_FILES)
73
74 def autocomplete_event(self, event):
Mark Dickinson934896d2009-02-21 20:59:32 +000075 """Happens when the user wants to complete his word, and if necessary,
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000076 open a completion list after that (if there is more than one
77 completion)
78 """
Terry Jan Reedyc665dfd2016-07-24 23:01:28 -040079 if hasattr(event, "mc_state") and event.mc_state or\
80 not self.text.get("insert linestart", "insert").strip():
81 # A modifier was pressed along with the tab or
82 # there is only previous whitespace on this line, so tab.
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -040083 return None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000084 if self.autocompletewindow and self.autocompletewindow.is_active():
85 self.autocompletewindow.complete()
86 return "break"
87 else:
88 opened = self.open_completions(False, True, True)
Terry Jan Reedyc665dfd2016-07-24 23:01:28 -040089 return "break" if opened else None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000090
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):
100 self._delayed_completion_id = None
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -0400101 if self.text.index("insert") == self._delayed_completion_index:
102 self.open_completions(*args)
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000103
104 def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
105 """Find the completions and create the AutoCompleteWindow.
106 Return True if successful (no syntax error or so found).
Louie Lu113d7352019-03-25 07:33:12 +0800107 If complete is True, then if there's nothing to complete and no
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000108 start of completion, won't open completions and return False.
109 If mode is given, will open a completion list only in this mode.
Louie Lu113d7352019-03-25 07:33:12 +0800110
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
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000115 """
116 # Cancel another delayed call, if it exists.
117 if self._delayed_completion_id is not None:
118 self.text.after_cancel(self._delayed_completion_id)
119 self._delayed_completion_id = None
120
121 hp = HyperParser(self.editwin, "insert")
122 curline = self.text.get("insert linestart", "insert")
123 i = j = len(curline)
124 if hp.is_in_string() and (not mode or mode==COMPLETE_FILES):
Louie Lu113d7352019-03-25 07:33:12 +0800125 # Find the beginning of the string.
126 # fetch_completions will look at the file system to determine
127 # whether the string value constitutes an actual file name
128 # XXX could consider raw strings here and unescape the string
129 # value if it's not raw.
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000130 self._remove_autocomplete_window()
131 mode = COMPLETE_FILES
Martin v. Löwis862d13a2012-06-03 11:55:32 +0200132 # Find last separator or string start
133 while i and curline[i-1] not in "'\"" + SEPS:
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000134 i -= 1
135 comp_start = curline[i:j]
136 j = i
Martin v. Löwis862d13a2012-06-03 11:55:32 +0200137 # Find string start
138 while i and curline[i-1] not in "'\"":
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000139 i -= 1
140 comp_what = curline[i:j]
141 elif hp.is_in_code() and (not mode or mode==COMPLETE_ATTRIBUTES):
142 self._remove_autocomplete_window()
143 mode = COMPLETE_ATTRIBUTES
Martin v. Löwis993fe3f2012-06-14 15:37:21 +0200144 while i and (curline[i-1] in ID_CHARS or ord(curline[i-1]) > 127):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000145 i -= 1
146 comp_start = curline[i:j]
147 if i and curline[i-1] == '.':
148 hp.set_index("insert-%dc" % (len(curline)-(i-1)))
149 comp_what = hp.get_expression()
150 if not comp_what or \
151 (not evalfuncs and comp_what.find('(') != -1):
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -0400152 return None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000153 else:
154 comp_what = ""
155 else:
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -0400156 return None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000157
158 if complete and not comp_what and not comp_start:
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -0400159 return None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000160 comp_lists = self.fetch_completions(comp_what, mode)
161 if not comp_lists[0]:
Terry Jan Reedyc74fb9c2016-07-24 20:35:43 -0400162 return None
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000163 self.autocompletewindow = self._make_autocomplete_window()
Serhiy Storchakadd4754e2013-09-11 22:46:27 +0300164 return not self.autocompletewindow.show_window(
165 comp_lists, "insert-%dc" % len(comp_start),
166 complete, mode, userWantsWin)
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000167
168 def fetch_completions(self, what, mode):
169 """Return a pair of lists of completions for something. The first list
170 is a sublist of the second. Both are sorted.
171
172 If there is a Python subprocess, get the comp. list there. Otherwise,
173 either fetch_completions() is running in the subprocess itself or it
174 was called in an IDLE EditorWindow before any script had been run.
175
176 The subprocess environment is that of the most recently run script. If
177 two unrelated modules are being edited some calltips in the current
178 module may be inoperative if the module was not the last to run.
179 """
180 try:
181 rpcclt = self.editwin.flist.pyshell.interp.rpcclt
182 except:
183 rpcclt = None
184 if rpcclt:
185 return rpcclt.remotecall("exec", "get_the_completion_list",
186 (what, mode), {})
187 else:
188 if mode == COMPLETE_ATTRIBUTES:
189 if what == "":
Terry Jan Reedy0fe45132019-03-24 17:12:28 -0400190 namespace = {**__main__.__builtins__.__dict__,
191 **__main__.__dict__}
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000192 bigl = eval("dir()", namespace)
193 bigl.sort()
194 if "__all__" in bigl:
Terry Jan Reedya77aa692012-02-05 14:31:16 -0500195 smalll = sorted(eval("__all__", namespace))
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000196 else:
Kurt B. Kaiserf2335a92007-08-10 02:41:21 +0000197 smalll = [s for s in bigl if s[:1] != '_']
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000198 else:
199 try:
200 entity = self.get_entity(what)
201 bigl = dir(entity)
202 bigl.sort()
203 if "__all__" in bigl:
Terry Jan Reedya77aa692012-02-05 14:31:16 -0500204 smalll = sorted(entity.__all__)
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000205 else:
Kurt B. Kaiserf2335a92007-08-10 02:41:21 +0000206 smalll = [s for s in bigl if s[:1] != '_']
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000207 except:
208 return [], []
209
210 elif mode == COMPLETE_FILES:
211 if what == "":
212 what = "."
213 try:
214 expandedpath = os.path.expanduser(what)
215 bigl = os.listdir(expandedpath)
216 bigl.sort()
Kurt B. Kaiserf2335a92007-08-10 02:41:21 +0000217 smalll = [s for s in bigl if s[:1] != '.']
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000218 except OSError:
219 return [], []
220
221 if not smalll:
222 smalll = bigl
223 return smalll, bigl
224
225 def get_entity(self, name):
Terry Jan Reedy0fe45132019-03-24 17:12:28 -0400226 "Lookup name in a namespace spanning sys.modules and __main.dict__."
227 return eval(name, {**sys.modules, **__main__.__dict__})
Terry Jan Reedye3fcfc22014-06-03 20:54:21 -0400228
229
wohlganger58fc71c2017-09-10 16:19:47 -0500230AutoComplete.reload()
231
Terry Jan Reedye3fcfc22014-06-03 20:54:21 -0400232if __name__ == '__main__':
233 from unittest import main
234 main('idlelib.idle_test.test_autocomplete', verbosity=2)