예제 #1
0
def pylsp_signature_help(document, position):
    code_position = _utils.position_to_jedi_linecolumn(document, position)
    signatures = document.jedi_script().get_signatures(**code_position)

    if not signatures:
        return {'signatures': []}

    s = signatures[0]

    # Docstring contains one or more lines of signature, followed by empty line, followed by docstring
    function_sig_lines = (s.docstring().split('\n\n') or [''])[0].splitlines()
    function_sig = ' '.join([line.strip() for line in function_sig_lines])
    sig = {
        'label': function_sig,
        'documentation': _utils.format_docstring(s.docstring(raw=True))
    }

    # If there are params, add those
    if s.params:
        sig['parameters'] = [{
            'label': p.name,
            'documentation': _param_docs(s.docstring(), p.name)
        } for p in s.params]

    # We only return a single signature because Python doesn't allow overloading
    sig_info = {'signatures': [sig], 'activeSignature': 0}

    if s.index is not None and s.params:
        # Then we know which parameter we're looking at
        sig_info['activeParameter'] = s.index

    return sig_info
예제 #2
0
def pylsp_completions(config, document, position):
    """Get formatted completions for current code position"""
    settings = config.plugin_settings('jedi_completion', document_path=document.path)
    code_position = _utils.position_to_jedi_linecolumn(document, position)

    code_position["fuzzy"] = settings.get("fuzzy", False)
    completions = document.jedi_script(use_document_path=True).complete(**code_position)

    if not completions:
        return None

    completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {})
    snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport')

    should_include_params = settings.get('include_params')
    should_include_class_objects = settings.get('include_class_objects', True)

    include_params = snippet_support and should_include_params and use_snippets(document, position)
    include_class_objects = snippet_support and should_include_class_objects and use_snippets(document, position)

    ready_completions = [
        _format_completion(c, include_params)
        for c in completions
    ]

    if include_class_objects:
        for c in completions:
            if c.type == 'class':
                completion_dict = _format_completion(c, False)
                completion_dict['kind'] = lsp.CompletionItemKind.TypeParameter
                completion_dict['label'] += ' object'
                ready_completions.append(completion_dict)

    return ready_completions or None
def pylsp_rename(config, workspace, document, position, new_name):  # pylint: disable=unused-argument
    log.debug('Executing rename of %s to %s', document.word_at_position(position), new_name)
    kwargs = _utils.position_to_jedi_linecolumn(document, position)
    kwargs['new_name'] = new_name
    try:
        refactoring = document.jedi_script().rename(**kwargs)
    except NotImplementedError as exc:
        raise Exception('No support for renaming in Python 2/3.5 with Jedi. '
                        'Consider using the rope_rename plugin instead') from exc
    log.debug('Finished rename: %s', refactoring.get_diff())
    changes = []
    for file_path, changed_file in refactoring.get_changed_files().items():
        uri = uris.from_fs_path(str(file_path))
        doc = workspace.get_maybe_document(uri)
        changes.append({
            'textDocument': {
                'uri': uri,
                'version': doc.version if doc else None
            },
            'edits': [
                {
                    'range': {
                        'start': {'line': 0, 'character': 0},
                        'end': {
                            'line': _num_lines(changed_file.get_new_code()),
                            'character': 0,
                        },
                    },
                    'newText': changed_file.get_new_code(),
                }
            ],
        })
    return {'documentChanges': changes}
예제 #4
0
def pylsp_references(document, position, exclude_declaration=False):
    code_position = _utils.position_to_jedi_linecolumn(document, position)
    usages = document.jedi_script().get_references(**code_position)

    if exclude_declaration:
        # Filter out if the usage is the actual declaration of the thing
        usages = [d for d in usages if not d.is_definition()]

    # Filter out builtin modules
    return [{
        'uri': uris.uri_with(document.uri, path=str(d.module_path)) if d.module_path else document.uri,
        'range': {
            'start': {'line': d.line - 1, 'character': d.column},
            'end': {'line': d.line - 1, 'character': d.column + len(d.name)}
        }
    } for d in usages if not d.in_builtin_module()]
예제 #5
0
def pylsp_document_highlight(document, position):
    code_position = _utils.position_to_jedi_linecolumn(document, position)
    usages = document.jedi_script().get_references(**code_position)

    def is_valid(definition):
        return definition.line is not None and definition.column is not None

    def local_to_document(definition):
        return not definition.module_path or str(definition.module_path) == document.path

    return [{
        'range': {
            'start': {'line': d.line - 1, 'character': d.column},
            'end': {'line': d.line - 1, 'character': d.column + len(d.name)}
        },
        'kind': lsp.DocumentHighlightKind.Write if d.is_definition() else lsp.DocumentHighlightKind.Read
    } for d in usages if is_valid(d) and local_to_document(d)]
예제 #6
0
def pylsp_definitions(config, document, position):
    settings = config.plugin_settings('jedi_definition')
    code_position = _utils.position_to_jedi_linecolumn(document, position)
    definitions = document.jedi_script(use_document_path=True).goto(
        follow_imports=settings.get('follow_imports', True),
        follow_builtin_imports=settings.get('follow_builtin_imports', True),
        **code_position)

    return [
        {
            'uri': uris.uri_with(document.uri, path=str(d.module_path)),
            'range': {
                'start': {'line': d.line - 1, 'character': d.column},
                'end': {'line': d.line - 1, 'character': d.column + len(d.name)},
            }
        }
        for d in definitions if d.is_definition() and _not_internal_definition(d)
    ]
예제 #7
0
def pylsp_hover(document, position):
    code_position = _utils.position_to_jedi_linecolumn(document, position)
    definitions = document.jedi_script().infer(**code_position)
    word = document.word_at_position(position)

    # Find first exact matching definition
    definition = next((x for x in definitions if x.name == word), None)

    # Ensure a definition is used if only one is available
    # even if the word doesn't match. An example of this case is 'np'
    # where 'numpy' doesn't match with 'np'. Same for NumPy ufuncs
    if len(definitions) == 1:
        definition = definitions[0]

    if not definition:
        return {'contents': ''}

    # raw docstring returns only doc, without signature
    doc = _utils.format_docstring(definition.docstring(raw=True))

    # Find first exact matching signature
    signature = next(
        (x.to_string() for x in definition.get_signatures() if x.name == word),
        '')

    contents = []
    if signature:
        contents.append({
            'language': 'python',
            'value': signature,
        })

    if doc:
        contents.append(doc)

    if not contents:
        return {'contents': ''}

    return {'contents': contents}
예제 #8
0
def pylsp_completions(config, document, position):
    """Get formatted completions for current code position"""
    # pylint: disable=too-many-locals
    settings = config.plugin_settings('jedi_completion',
                                      document_path=document.path)
    resolve_eagerly = settings.get('eager', False)
    code_position = _utils.position_to_jedi_linecolumn(document, position)

    code_position['fuzzy'] = settings.get('fuzzy', False)
    completions = document.jedi_script(use_document_path=True).complete(
        **code_position)

    if not completions:
        return None

    completion_capabilities = config.capabilities.get('textDocument', {}).get(
        'completion', {})
    snippet_support = completion_capabilities.get('completionItem',
                                                  {}).get('snippetSupport')

    should_include_params = settings.get('include_params')
    should_include_class_objects = settings.get('include_class_objects', True)

    max_to_resolve = settings.get('resolve_at_most', 25)
    modules_to_cache_for = settings.get('cache_for', None)
    if modules_to_cache_for is not None:
        LABEL_RESOLVER.cached_modules = modules_to_cache_for
        SNIPPET_RESOLVER.cached_modules = modules_to_cache_for

    include_params = snippet_support and should_include_params and use_snippets(
        document, position)
    include_class_objects = snippet_support and should_include_class_objects and use_snippets(
        document, position)

    ready_completions = [
        _format_completion(c,
                           include_params,
                           resolve=resolve_eagerly,
                           resolve_label_or_snippet=(i < max_to_resolve))
        for i, c in enumerate(completions)
    ]

    # TODO split up once other improvements are merged
    if include_class_objects:
        for i, c in enumerate(completions):
            if c.type == 'class':
                completion_dict = _format_completion(
                    c,
                    False,
                    resolve=resolve_eagerly,
                    resolve_label_or_snippet=(i < max_to_resolve))
                completion_dict['kind'] = lsp.CompletionItemKind.TypeParameter
                completion_dict['label'] += ' object'
                ready_completions.append(completion_dict)

    for completion_dict in ready_completions:
        completion_dict['data'] = {'doc_uri': document.uri}

    # most recently retrieved completion items, used for resolution
    document.shared_data['LAST_JEDI_COMPLETIONS'] = {
        # label is the only required property; here it is assumed to be unique
        completion['label']: (completion, data)
        for completion, data in zip(ready_completions, completions)
    }

    return ready_completions or None