| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | # Copyright (c) 2009 www.stani.be (GPL license) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 00:01:15 +00:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-02-08 00:01:15 +00:00
										 |  |  | #  This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | #  modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | #  as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | #  of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-02-08 00:01:15 +00:00
										 |  |  | #  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | #  GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | #  along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-13 14:38:30 +00:00
										 |  |  | # <pep8-80 compliant> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | """This module provides intellisense features such as:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * autocompletion | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  | * calltips | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | It unifies all completion plugins and only loads them on demand. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | # TODO: file complete if startswith quotes | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # regular expressions to find out which completer we need | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # line which starts with an import statement | 
					
						
							| 
									
										
										
										
											2010-02-14 12:23:25 +00:00
										 |  |  | RE_MODULE = re.compile('^import(\s|$)|from.+') | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-30 09:34:57 +00:00
										 |  |  | # The following regular expression means an 'unquoted' word | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | RE_UNQUOTED_WORD = re.compile( | 
					
						
							| 
									
										
										
										
											2009-10-30 09:34:57 +00:00
										 |  |  |     # don't start with a quote | 
					
						
							|  |  |  |     '''(?:^|[^"'a-zA-Z0-9_])''' | 
					
						
							|  |  |  |     # start with a \w = [a-zA-Z0-9_] | 
					
						
							|  |  |  |     '''((?:\w+''' | 
					
						
							|  |  |  |     # allow also dots and closed bracket pairs [] | 
					
						
							|  |  |  |     '''(?:\w|[.]|\[.+?\])*''' | 
					
						
							|  |  |  |     # allow empty string | 
					
						
							|  |  |  |     '''|)''' | 
					
						
							|  |  |  |     # allow an unfinished index at the end (including quotes) | 
					
						
							|  |  |  |     '''(?:\[[^\]]*$)?)$''', | 
					
						
							|  |  |  |     # allow unicode as theoretically this is possible | 
					
						
							|  |  |  |     re.UNICODE) | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 10:47:43 +00:00
										 |  |  | def complete(line, cursor, namespace, private): | 
					
						
							| 
									
										
										
										
											2009-10-30 09:34:57 +00:00
										 |  |  |     """Returns a list of possible completions:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * name completion | 
					
						
							|  |  |  |     * attribute completion (obj.attr) | 
					
						
							|  |  |  |     * index completion for lists and dictionaries | 
					
						
							|  |  |  |     * module completion (from/import) | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     :param line: incomplete text line | 
					
						
							|  |  |  |     :type line: str | 
					
						
							|  |  |  |     :param cursor: current character position | 
					
						
							|  |  |  |     :type cursor: int | 
					
						
							|  |  |  |     :param namespace: namespace | 
					
						
							|  |  |  |     :type namespace: dict | 
					
						
							|  |  |  |     :param private: whether private variables should be listed | 
					
						
							|  |  |  |     :type private: bool | 
					
						
							|  |  |  |     :returns: list of completions, word | 
					
						
							|  |  |  |     :rtype: list, str | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     >>> complete('re.sr', 5, {'re': re}) | 
					
						
							|  |  |  |     (['re.sre_compile', 're.sre_parse'], 're.sr') | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     re_unquoted_word = RE_UNQUOTED_WORD.search(line[:cursor]) | 
					
						
							|  |  |  |     if re_unquoted_word: | 
					
						
							|  |  |  |         # unquoted word -> module or attribute completion | 
					
						
							|  |  |  |         word = re_unquoted_word.group(1) | 
					
						
							|  |  |  |         if RE_MODULE.match(line): | 
					
						
							| 
									
										
										
										
											2010-10-18 13:16:43 +00:00
										 |  |  |             from . import complete_import | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |             matches = complete_import.complete(line) | 
					
						
							| 
									
										
										
										
											2011-06-29 10:47:43 +00:00
										 |  |  |             if not private: | 
					
						
							|  |  |  |                 matches[:] = [m for m in matches if m[:1] != "_"] | 
					
						
							|  |  |  |             matches.sort() | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2010-10-18 13:16:43 +00:00
										 |  |  |             from . import complete_namespace | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |             matches = complete_namespace.complete(word, namespace, private) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         # for now we don't have completers for strings | 
					
						
							|  |  |  |         # TODO: add file auto completer for strings | 
					
						
							|  |  |  |         word = '' | 
					
						
							|  |  |  |         matches = [] | 
					
						
							|  |  |  |     return matches, word | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def expand(line, cursor, namespace, private=True): | 
					
						
							|  |  |  |     """This method is invoked when the user asks autocompletion,
 | 
					
						
							|  |  |  |     e.g. when Ctrl+Space is clicked. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param line: incomplete text line | 
					
						
							|  |  |  |     :type line: str | 
					
						
							|  |  |  |     :param cursor: current character position | 
					
						
							|  |  |  |     :type cursor: int | 
					
						
							|  |  |  |     :param namespace: namespace | 
					
						
							|  |  |  |     :type namespace: dict | 
					
						
							|  |  |  |     :param private: whether private variables should be listed | 
					
						
							|  |  |  |     :type private: bool | 
					
						
							|  |  |  |     :returns: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         current expanded line, updated cursor position and scrollback | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :rtype: str, int, str | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     >>> expand('os.path.isdir(', 14, {'os': os})[-1] | 
					
						
							|  |  |  |     'isdir(s)\\nReturn true if the pathname refers to an existing directory.' | 
					
						
							|  |  |  |     >>> expand('abs(', 4, {})[-1] | 
					
						
							|  |  |  |     'abs(number) -> number\\nReturn the absolute value of the argument.' | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  |     if line[:cursor].strip().endswith('('): | 
					
						
							| 
									
										
										
										
											2010-10-18 13:16:43 +00:00
										 |  |  |         from . import complete_calltip | 
					
						
							| 
									
										
										
										
											2016-07-29 21:22:27 +10:00
										 |  |  |         matches, word, scrollback = complete_calltip.complete( | 
					
						
							|  |  |  |             line, cursor, namespace) | 
					
						
							| 
									
										
										
										
											2011-06-11 17:03:26 +00:00
										 |  |  |         prefix = os.path.commonprefix(matches)[len(word):] | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  |         no_calltip = False | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         matches, word = complete(line, cursor, namespace, private) | 
					
						
							| 
									
										
										
										
											2011-06-11 17:03:26 +00:00
										 |  |  |         prefix = os.path.commonprefix(matches)[len(word):] | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  |         if len(matches) == 1: | 
					
						
							|  |  |  |             scrollback = '' | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2011-06-10 07:22:35 +00:00
										 |  |  |             # causes blender bug [#27495] since string keys may contain '.' | 
					
						
							|  |  |  |             # scrollback = '  '.join([m.split('.')[-1] for m in matches]) | 
					
						
							| 
									
										
										
										
											2011-06-29 06:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # add white space to align with the cursor | 
					
						
							|  |  |  |             white_space = "    " + (" " * (cursor + len(prefix))) | 
					
						
							| 
									
										
										
										
											2011-06-11 17:03:26 +00:00
										 |  |  |             word_prefix = word + prefix | 
					
						
							| 
									
										
										
										
											2011-06-29 06:06:59 +00:00
										 |  |  |             scrollback = '\n'.join( | 
					
						
							| 
									
										
										
										
											2016-07-29 21:22:27 +10:00
										 |  |  |                 [white_space + m[len(word_prefix):] | 
					
						
							|  |  |  |                  if (word_prefix and m.startswith(word_prefix)) | 
					
						
							|  |  |  |                  else | 
					
						
							|  |  |  |                  white_space + m.split('.')[-1] | 
					
						
							|  |  |  |                  for m in matches]) | 
					
						
							| 
									
										
										
										
											2011-06-10 07:22:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  |         no_calltip = True | 
					
						
							| 
									
										
										
										
											2011-06-11 17:03:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |     if prefix: | 
					
						
							|  |  |  |         line = line[:cursor] + prefix + line[cursor:] | 
					
						
							| 
									
										
										
										
											2013-02-24 21:51:48 +00:00
										 |  |  |         cursor += len(prefix.encode('utf-8')) | 
					
						
							| 
									
										
										
										
											2009-11-06 08:53:07 +00:00
										 |  |  |         if no_calltip and prefix.endswith('('): | 
					
						
							|  |  |  |             return expand(line, cursor, namespace, private) | 
					
						
							| 
									
										
										
										
											2009-10-29 20:55:45 +00:00
										 |  |  |     return line, cursor, scrollback |