Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bpython/autocomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ def locate(self, current_offset, line):
def format(self, word):
return after_last_dot(word)

def try_to_import(self, module_name):
return importcompletion.try_to_import(module_name)


class FilenameCompletion(BaseCompletionType):
def __init__(self, mode=SIMPLE):
Expand Down
3 changes: 3 additions & 0 deletions bpython/curtsies.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ def __init__(self, config, locals_, banner, interp=None):
self.request_undo = self.input_generator.event_trigger(
bpythonevents.UndoEvent
)
self.background_import_event = self.input_generator.event_trigger(
bpythonevents.BackgroundImportEvent
)

with self.input_generator:
pass # temp hack to get .original_stty
Expand Down
7 changes: 7 additions & 0 deletions bpython/curtsiesfrontend/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ class UndoEvent(curtsies.events.Event):

def __init__(self, n=1):
self.n = n


class BackgroundImportEvent(curtsies.events.Event):
"""Background import for advanced auto complete."""

def __init__(self, module_name):
self.module_name = module_name
22 changes: 22 additions & 0 deletions bpython/curtsiesfrontend/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from bpython import autocomplete
from bpython.translations import _
from bpython.pager import get_pager_command
from bpython.line import from_import_tab

from bpython.curtsiesfrontend import replpainter as paint
from bpython.curtsiesfrontend import sitefix
Expand Down Expand Up @@ -690,6 +691,13 @@ def process_control_event(self, e):
% (time.strftime("%X"), " & ".join(e.files_modified))
)

elif isinstance(e, bpythonevents.BackgroundImportEvent):
# self.comleters[1] should match to autocomplete's ImportCompletion class
self.completers[1].try_to_import(e.module_name)
self.status_bar.pop_permanent_message(
"Imported module %s" % e.module_name
)

else:
raise ValueError("Don't know how to handle event type: %r" % e)

Expand Down Expand Up @@ -872,6 +880,7 @@ def on_tab(self, back=False):
2) complete the current word with characters common to all completions
3) select the first or last match
4) select the next or previous match if already have a match
5) if line is `from <module> import` and tab then import module and attr
"""

def only_whitespace_left_of_cursor():
Expand All @@ -888,6 +897,19 @@ def only_whitespace_left_of_cursor():
self.add_normal_character(" ")
return

# 5. if line is `from a import` and tab then import module and attr
line = self.current_line.split()
module_name = ""
if "from" in line and "import" in line:
# returns <module> name if the line contains: "from <module> import"
module_name = from_import_tab(self.current_line)
if module_name:
if module_name not in sys.modules:
self.status_bar.push_permanent_message(
"Imported module %s" % module_name
)
self.background_import_event(module_name=module_name)

# run complete() if we don't already have matches
if len(self.matches_iter.matches) == 0:
self.list_win_visible = self.complete(tab=True)
Expand Down
14 changes: 14 additions & 0 deletions bpython/importcompletion.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import fnmatch
import os
import sys
import importlib
import warnings
import importlib.machinery

Expand Down Expand Up @@ -91,6 +92,19 @@ def module_attr_matches(name):
return attr_matches(name, prefix="", only_modules=True)


def try_to_import(module_name):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really necessary? Shouldn't those modules already be found by our normal module processing routines?

"""Called by curtsiesfrontend repl on tab to import module
in background for better auto completion: attr completion"""
try:
module = __import__(module_name)
module_path = os.path.dirname(module.__file__)
for mod in find_modules(module_path):
modules.add("%s.%s" % (module_name, mod))
modules.add(module_name)
except ImportError:
pass


def complete(cursor_offset, line):
"""Construct a full list of possibly completions for imports."""
tokens = line.split()
Expand Down
13 changes: 13 additions & 0 deletions bpython/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ def current_object_attribute(cursor_offset, line):
return None


from_import_tab_re = LazyReCompile(r"from ([\w0-9_.]*)\s+import")


def from_import_tab(line):
matches = from_import_tab_re.finditer(line)
try:
module = next(matches)
except StopIteration:
pass
if module:
return str(module[1])


current_from_import_from_re = LazyReCompile(
r"from ([\w0-9_.]*)(?:\s+import\s+([\w0-9_]+[,]?\s*)+)*"
)
Expand Down