4242# Types of parso nodes for which snippet is not included in the completion
4343_IMPORTS = ('import_name' , 'import_from' )
4444
45+ # Types of parso node for errors
46+ _ERRORS = ('error_node' , )
47+
4548
4649@hookimpl
4750def pyls_completions (config , document , position ):
@@ -63,11 +66,25 @@ def pyls_completions(config, document, position):
6366
6467 settings = config .plugin_settings ('jedi_completion' , document_path = document .path )
6568 should_include_params = settings .get ('include_params' )
66- include_params = (snippet_support and should_include_params and
67- use_snippets (document , position ))
69+ include_params = snippet_support and should_include_params and use_snippets (document , position )
6870 return [_format_completion (d , include_params ) for d in definitions ] or None
6971
7072
73+ def is_exception_class (name ):
74+ """
75+ Determine if a class name is an instance of an Exception.
76+
77+ This returns `False` if the name given corresponds with a instance of
78+ the 'Exception' class, `True` otherwise
79+ """
80+ try :
81+ return name in [cls .__name__ for cls in Exception .__subclasses__ ()]
82+ except AttributeError :
83+ # Needed in case a class don't uses new-style
84+ # class definition in Python 2
85+ return False
86+
87+
7188def use_snippets (document , position ):
7289 """
7390 Determine if it's necessary to return snippets in code completions.
@@ -79,15 +96,28 @@ def use_snippets(document, position):
7996 lines = document .source .split ('\n ' , line )
8097 act_lines = [lines [line ][:position ['character' ]]]
8198 line -= 1
99+ last_character = ''
82100 while line > - 1 :
83101 act_line = lines [line ]
84- if act_line .rstrip ().endswith ('\\ ' ):
102+ if (act_line .rstrip ().endswith ('\\ ' ) or
103+ act_line .rstrip ().endswith ('(' ) or
104+ act_line .rstrip ().endswith (',' )):
85105 act_lines .insert (0 , act_line )
86106 line -= 1
107+ if act_line .rstrip ().endswith ('(' ):
108+ # Needs to be added to the end of the code before parsing
109+ # to make it valid, otherwise the node type could end
110+ # being an 'error_node' for multi-line imports that use '('
111+ last_character = ')'
87112 else :
88113 break
89- tokens = parso .parse ('\n ' .join (act_lines ).split (';' )[- 1 ].strip ())
90- return tokens .children [0 ].type not in _IMPORTS
114+ if '(' in act_lines [- 1 ].strip ():
115+ last_character = ')'
116+ code = '\n ' .join (act_lines ).split (';' )[- 1 ].strip () + last_character
117+ tokens = parso .parse (code )
118+ expr_type = tokens .children [0 ].type
119+ return (expr_type not in _IMPORTS and
120+ not (expr_type in _ERRORS and 'import' in code ))
91121
92122
93123def _format_completion (d , include_params = True ):
@@ -100,19 +130,25 @@ def _format_completion(d, include_params=True):
100130 'insertText' : d .name
101131 }
102132
103- if include_params and hasattr (d , 'params' ) and d .params :
133+ if (include_params and hasattr (d , 'params' ) and d .params and
134+ not is_exception_class (d .name )):
104135 positional_args = [param for param in d .params if '=' not in param .description ]
105136
106- # For completions with params, we can generate a snippet instead
107- completion ['insertTextFormat' ] = lsp .InsertTextFormat .Snippet
108- snippet = d .name + '('
109- for i , param in enumerate (positional_args ):
110- name = param .name if param .name != '/' else '\\ /'
111- snippet += '${%s:%s}' % (i + 1 , name )
112- if i < len (positional_args ) - 1 :
113- snippet += ', '
114- snippet += ')$0'
115- completion ['insertText' ] = snippet
137+ if len (positional_args ) > 1 :
138+ # For completions with params, we can generate a snippet instead
139+ completion ['insertTextFormat' ] = lsp .InsertTextFormat .Snippet
140+ snippet = d .name + '('
141+ for i , param in enumerate (positional_args ):
142+ name = param .name if param .name != '/' else '\\ /'
143+ snippet += '${%s:%s}' % (i + 1 , name )
144+ if i < len (positional_args ) - 1 :
145+ snippet += ', '
146+ snippet += ')$0'
147+ completion ['insertText' ] = snippet
148+ elif len (positional_args ) == 1 :
149+ completion ['insertText' ] = d .name + '($0)'
150+ else :
151+ completion ['insertText' ] = d .name + '()'
116152
117153 return completion
118154
0 commit comments