Skip to content
This repository was archived by the owner on Aug 2, 2019. It is now read-only.

Commit 9ddf56a

Browse files
committed
add a modifiable copy of idlelib
1 parent 26056a4 commit 9ddf56a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

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

0 commit comments

Comments
 (0)