ยปCore Development>Code coverage>Lib/idlelib/autocomplete.py

Python code coverage for Lib/idlelib/autocomplete.py

#countcontent
1n/a"""autocomplete.py - An IDLE extension for automatically completing names.
2n/a
3n/aThis extension can complete either attribute names or file names. It can pop
4n/aa window with all available names, for the user to select from.
5n/a"""
6n/aimport os
7n/aimport string
8n/aimport sys
9n/a
10n/a# These constants represent the two different types of completions.
11n/a# They must be defined here so autocomple_w can import them.
12n/aCOMPLETE_ATTRIBUTES, COMPLETE_FILES = range(1, 2+1)
13n/a
14n/afrom idlelib import autocomplete_w
15n/afrom idlelib.config import idleConf
16n/afrom idlelib.hyperparser import HyperParser
17n/aimport __main__
18n/a
19n/a# This string includes all chars that may be in an identifier.
20n/a# TODO Update this here and elsewhere.
21n/aID_CHARS = string.ascii_letters + string.digits + "_"
22n/a
23n/aSEPS = os.sep
24n/aif os.altsep: # e.g. '/' on Windows...
25n/a SEPS += os.altsep
26n/a
27n/a
28n/aclass AutoComplete:
29n/a
30n/a menudefs = [
31n/a ('edit', [
32n/a ("Show Completions", "<<force-open-completions>>"),
33n/a ])
34n/a ]
35n/a
36n/a popupwait = idleConf.GetOption("extensions", "AutoComplete",
37n/a "popupwait", type="int", default=0)
38n/a
39n/a def __init__(self, editwin=None):
40n/a self.editwin = editwin
41n/a if editwin is not None: # not in subprocess or test
42n/a self.text = editwin.text
43n/a self.autocompletewindow = None
44n/a # id of delayed call, and the index of the text insert when
45n/a # the delayed call was issued. If _delayed_completion_id is
46n/a # None, there is no delayed call.
47n/a self._delayed_completion_id = None
48n/a self._delayed_completion_index = None
49n/a
50n/a def _make_autocomplete_window(self):
51n/a return autocomplete_w.AutoCompleteWindow(self.text)
52n/a
53n/a def _remove_autocomplete_window(self, event=None):
54n/a if self.autocompletewindow:
55n/a self.autocompletewindow.hide_window()
56n/a self.autocompletewindow = None
57n/a
58n/a def force_open_completions_event(self, event):
59n/a """Happens when the user really wants to open a completion list, even
60n/a if a function call is needed.
61n/a """
62n/a self.open_completions(True, False, True)
63n/a
64n/a def try_open_completions_event(self, event):
65n/a """Happens when it would be nice to open a completion list, but not
66n/a really necessary, for example after a dot, so function
67n/a calls won't be made.
68n/a """
69n/a lastchar = self.text.get("insert-1c")
70n/a if lastchar == ".":
71n/a self._open_completions_later(False, False, False,
72n/a COMPLETE_ATTRIBUTES)
73n/a elif lastchar in SEPS:
74n/a self._open_completions_later(False, False, False,
75n/a COMPLETE_FILES)
76n/a
77n/a def autocomplete_event(self, event):
78n/a """Happens when the user wants to complete his word, and if necessary,
79n/a open a completion list after that (if there is more than one
80n/a completion)
81n/a """
82n/a if hasattr(event, "mc_state") and event.mc_state or\
83n/a not self.text.get("insert linestart", "insert").strip():
84n/a # A modifier was pressed along with the tab or
85n/a # there is only previous whitespace on this line, so tab.
86n/a return None
87n/a if self.autocompletewindow and self.autocompletewindow.is_active():
88n/a self.autocompletewindow.complete()
89n/a return "break"
90n/a else:
91n/a opened = self.open_completions(False, True, True)
92n/a return "break" if opened else None
93n/a
94n/a def _open_completions_later(self, *args):
95n/a self._delayed_completion_index = self.text.index("insert")
96n/a if self._delayed_completion_id is not None:
97n/a self.text.after_cancel(self._delayed_completion_id)
98n/a self._delayed_completion_id = \
99n/a self.text.after(self.popupwait, self._delayed_open_completions,
100n/a *args)
101n/a
102n/a def _delayed_open_completions(self, *args):
103n/a self._delayed_completion_id = None
104n/a if self.text.index("insert") == self._delayed_completion_index:
105n/a self.open_completions(*args)
106n/a
107n/a def open_completions(self, evalfuncs, complete, userWantsWin, mode=None):
108n/a """Find the completions and create the AutoCompleteWindow.
109n/a Return True if successful (no syntax error or so found).
110n/a if complete is True, then if there's nothing to complete and no
111n/a start of completion, won't open completions and return False.
112n/a If mode is given, will open a completion list only in this mode.
113n/a """
114n/a # Cancel another delayed call, if it exists.
115n/a if self._delayed_completion_id is not None:
116n/a self.text.after_cancel(self._delayed_completion_id)
117n/a self._delayed_completion_id = None
118n/a
119n/a hp = HyperParser(self.editwin, "insert")
120n/a curline = self.text.get("insert linestart", "insert")
121n/a i = j = len(curline)
122n/a if hp.is_in_string() and (not mode or mode==COMPLETE_FILES):
123n/a # Find the beginning of the string
124n/a # fetch_completions will look at the file system to determine whether the
125n/a # string value constitutes an actual file name
126n/a # XXX could consider raw strings here and unescape the string value if it's
127n/a # not raw.
128n/a self._remove_autocomplete_window()
129n/a mode = COMPLETE_FILES
130n/a # Find last separator or string start
131n/a while i and curline[i-1] not in "'\"" + SEPS:
132n/a i -= 1
133n/a comp_start = curline[i:j]
134n/a j = i
135n/a # Find string start
136n/a while i and curline[i-1] not in "'\"":
137n/a i -= 1
138n/a comp_what = curline[i:j]
139n/a elif hp.is_in_code() and (not mode or mode==COMPLETE_ATTRIBUTES):
140n/a self._remove_autocomplete_window()
141n/a mode = COMPLETE_ATTRIBUTES
142n/a while i and (curline[i-1] in ID_CHARS or ord(curline[i-1]) > 127):
143n/a i -= 1
144n/a comp_start = curline[i:j]
145n/a if i and curline[i-1] == '.':
146n/a hp.set_index("insert-%dc" % (len(curline)-(i-1)))
147n/a comp_what = hp.get_expression()
148n/a if not comp_what or \
149n/a (not evalfuncs and comp_what.find('(') != -1):
150n/a return None
151n/a else:
152n/a comp_what = ""
153n/a else:
154n/a return None
155n/a
156n/a if complete and not comp_what and not comp_start:
157n/a return None
158n/a comp_lists = self.fetch_completions(comp_what, mode)
159n/a if not comp_lists[0]:
160n/a return None
161n/a self.autocompletewindow = self._make_autocomplete_window()
162n/a return not self.autocompletewindow.show_window(
163n/a comp_lists, "insert-%dc" % len(comp_start),
164n/a complete, mode, userWantsWin)
165n/a
166n/a def fetch_completions(self, what, mode):
167n/a """Return a pair of lists of completions for something. The first list
168n/a is a sublist of the second. Both are sorted.
169n/a
170n/a If there is a Python subprocess, get the comp. list there. Otherwise,
171n/a either fetch_completions() is running in the subprocess itself or it
172n/a was called in an IDLE EditorWindow before any script had been run.
173n/a
174n/a The subprocess environment is that of the most recently run script. If
175n/a two unrelated modules are being edited some calltips in the current
176n/a module may be inoperative if the module was not the last to run.
177n/a """
178n/a try:
179n/a rpcclt = self.editwin.flist.pyshell.interp.rpcclt
180n/a except:
181n/a rpcclt = None
182n/a if rpcclt:
183n/a return rpcclt.remotecall("exec", "get_the_completion_list",
184n/a (what, mode), {})
185n/a else:
186n/a if mode == COMPLETE_ATTRIBUTES:
187n/a if what == "":
188n/a namespace = __main__.__dict__.copy()
189n/a namespace.update(__main__.__builtins__.__dict__)
190n/a bigl = eval("dir()", namespace)
191n/a bigl.sort()
192n/a if "__all__" in bigl:
193n/a smalll = sorted(eval("__all__", namespace))
194n/a else:
195n/a smalll = [s for s in bigl if s[:1] != '_']
196n/a else:
197n/a try:
198n/a entity = self.get_entity(what)
199n/a bigl = dir(entity)
200n/a bigl.sort()
201n/a if "__all__" in bigl:
202n/a smalll = sorted(entity.__all__)
203n/a else:
204n/a smalll = [s for s in bigl if s[:1] != '_']
205n/a except:
206n/a return [], []
207n/a
208n/a elif mode == COMPLETE_FILES:
209n/a if what == "":
210n/a what = "."
211n/a try:
212n/a expandedpath = os.path.expanduser(what)
213n/a bigl = os.listdir(expandedpath)
214n/a bigl.sort()
215n/a smalll = [s for s in bigl if s[:1] != '.']
216n/a except OSError:
217n/a return [], []
218n/a
219n/a if not smalll:
220n/a smalll = bigl
221n/a return smalll, bigl
222n/a
223n/a def get_entity(self, name):
224n/a """Lookup name in a namespace spanning sys.modules and __main.dict__"""
225n/a namespace = sys.modules.copy()
226n/a namespace.update(__main__.__dict__)
227n/a return eval(name, namespace)
228n/a
229n/a
230n/aif __name__ == '__main__':
231n/a from unittest import main
232n/a main('idlelib.idle_test.test_autocomplete', verbosity=2)