home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 June / maximum-cd-2011-06.iso / DiscContents / LibO_3.3.1_Win_x86_install_multi.exe / libreoffice1.cab / AutoComplete.py < prev    next >
Encoding:
Python Source  |  2011-02-15  |  8.8 KB  |  230 lines

  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 configHandler import idleConf
  11.  
  12. import AutoCompleteWindow
  13. from HyperParser import HyperParser
  14.  
  15. import __main__
  16.  
  17. # This string includes all chars that may be in a file name (without a path
  18. # separator)
  19. FILENAME_CHARS = string.ascii_letters + string.digits + os.curdir + "._~#$:-"
  20. # This string includes all chars that may be in an identifier
  21. ID_CHARS = string.ascii_letters + string.digits + "_"
  22.  
  23. # These constants represent the two different types of completions
  24. COMPLETE_ATTRIBUTES, COMPLETE_FILES = range(1, 2+1)
  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 neccesary, 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 neccesary,
  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 = filter(lambda s: s[:1] != '_', bigl)
  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 = filter(lambda s: s[:1] != '_', bigl)
  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 = filter(lambda s: s[:1] != '.', bigl)
  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)
  230.