Ejemplo n.º 1
0
    def target_object_to_completion_item(
        self, name: str, display_name: str, obj_type: str
    ) -> CompletionItem:
        """Convert a target object to its CompletionItem representation."""

        key = obj_type

        if ":" in key:
            _, key = key.split(":")

        target_type = COMPLETION_TARGETS.get(key, DEFAULT_TARGET)

        return CompletionItem(
            name,
            kind=target_type.kind,
            detail=str(display_name),
            insert_text=target_type.insert_fmt.format(name=name),
        )
Ejemplo n.º 2
0
    def options_to_completion_items(
            self, name: str, directive: Directive) -> List[CompletionItem]:
        """Convert a directive's options to a list of completion items.

        Unfortunately, the ``autoxxx`` family of directives are a little different.
        Each ``autoxxxx`` directive name resolves to the same ``AutodocDirective`` class.
        That paricular directive does not have any options, instead the options are
        held on the particular Documenter that documents that object type.

        This method does the lookup in order to determine what those options are.

        Parameters
        ----------
        name:
           The name of the directive as it appears in an rst file.
        directive:
           The directive whose options we are creating completions for.
        """

        options = directive.option_spec

        # autoxxx directives require special handlng.
        if name.startswith("auto") and self.rst.app:
            self.logger.debug("Processing options for '%s' directive", name)
            name = name.replace("auto", "")

            self.logger.debug("Documenter name is '%s'", name)
            documenter = self.rst.app.registry.documenters.get(name, None)

            if documenter is not None:
                options = documenter.option_spec

        if options is None:
            return []

        return [
            CompletionItem(
                opt,
                detail="option",
                kind=CompletionItemKind.Field,
                insert_text=f"{opt}: ",
            ) for opt in options
        ]
    def _build_node_completion_item(self, node: XsdNode, order: int = 0) -> CompletionItem:
        """Generates a completion item with the information about the
        given node definition.

        Args:
            node (XsdNode): The node definition used to build the
            completion item.
            order (int): The position for ordering this item.

        Returns:
            CompletionItem: The completion item with the basic information
            about the node.
        """
        return CompletionItem(
            node.name,
            CompletionItemKind.Class,
            documentation=node.get_doc(),
            sort_text=str(order).zfill(2),
        )
Ejemplo n.º 4
0
def lsp_completion_item(
    completion: Completion,
    char_before_cursor: str,
    enable_snippets: bool,
    resolve_eagerly: bool,
    markup_kind: MarkupKind,
) -> CompletionItem:
    """Using a Jedi completion, obtain a jedi completion item."""
    completion_name = completion.name
    name_clean = clean_completion_name(completion_name, char_before_cursor)
    lsp_type = get_lsp_completion_type(completion.type)
    completion_item = CompletionItem(
        label=completion_name,
        filter_text=completion_name,
        kind=lsp_type,
        sort_text=complete_sort_name(completion),
        insert_text=name_clean,
        insert_text_format=InsertTextFormat.PlainText,
    )

    _MOST_RECENT_COMPLETIONS[completion_name] = completion
    if resolve_eagerly:
        completion_item = lsp_completion_item_resolve(
            completion_item, markup_kind=markup_kind
        )

    if not enable_snippets:
        return completion_item
    if lsp_type not in _LSP_TYPE_FOR_SNIPPET:
        return completion_item

    signatures = completion.get_signatures()
    if not signatures:
        return completion_item

    try:
        snippet_signature = get_snippet_signature(signatures[0])
    except Exception:  # pylint: disable=broad-except
        return completion_item
    new_text = completion_name + snippet_signature
    completion_item.insertText = new_text
    completion_item.insertTextFormat = InsertTextFormat.Snippet
    return completion_item
    def _build_attribute_completion_item(self, attr: XsdAttribute, order: int = 0) -> CompletionItem:
        """Generates a completion item with the information about the
        given attribute definition.

        Args:
            attr (XsdAttribute): The attribute definition used to build the
            completion item.
            order (int): The position for ordering this item.

        Returns:
            CompletionItem: The completion item with the basic information
            about the attribute.
        """
        return CompletionItem(
            attr.name,
            CompletionItemKind.Variable,
            documentation=attr.get_doc(),
            insert_text=f'{attr.name}="$1"',
            insert_text_format=InsertTextFormat.Snippet,
            sort_text=str(order).zfill(2),
        )
Ejemplo n.º 6
0
    def target_to_completion_item(self, label: str, target,
                                  target_type: str) -> CompletionItem:

        key = target_type

        if ":" in key:
            key = ":".join(key.split(":")[1:])

        completion_type = COMPLETION_TARGETS.get(key, DEFAULT_TARGET)
        source, version, _, display = target

        if display == "-":
            display = label

        if version:
            version = f" v{version}"

        detail = f"{display} - {source}{version}"

        return CompletionItem(label,
                              kind=completion_type.kind,
                              detail=detail,
                              insert_text=label)
Ejemplo n.º 7
0
def lsp_completion_item(
    name: Completion,
    char_before_cursor: str,
    enable_snippets: bool,
    markup_kind: MarkupKind,
) -> CompletionItem:
    """Using a Jedi completion, obtain a jedi completion item."""
    name_name = name.name
    name_clean = clean_completion_name(name_name, char_before_cursor)
    lsp_type = get_lsp_completion_type(name.type)
    completion_item = CompletionItem(
        label=name_name,
        filter_text=name_name,
        kind=lsp_type,
        detail=name.description,
        documentation=MarkupContent(kind=markup_kind, value=name.docstring()),
        sort_text=complete_sort_name(name),
        insert_text=name_clean,
        insert_text_format=InsertTextFormat.PlainText,
    )
    if not enable_snippets:
        return completion_item
    if lsp_type not in _LSP_TYPE_FOR_SNIPPET:
        return completion_item

    signatures = name.get_signatures()
    if not signatures:
        return completion_item

    try:
        snippet_signature = get_snippet_signature(signatures[0])
    except Exception:  # pylint: disable=broad-except
        return completion_item
    new_text = name_name + snippet_signature
    completion_item.insertText = new_text
    completion_item.insertTextFormat = InsertTextFormat.Snippet
    return completion_item
Ejemplo n.º 8
0
    def directive_to_completion_item(self, name: str, directive: Directive,
                                     match: "re.Match",
                                     position: Position) -> CompletionItem:
        """Convert an rst directive to its CompletionItem representation.

        Previously, it was fine to pre-convert directives into their completion item
        representation during the :meth:`discover` phase. However a number of factors
        combined to force this to be something we have to compute specifically for each
        completion site.

        It all stems from directives that live under a namespaced domain e.g.
        ``.. c:macro::``. First in order to get trigger character completions for
        directives, we need to allow users to start typing the directive name
        immediately after the second dot and have the CompletionItem insert the leading
        space. Which is exactly what we used to do, setting
        ``insert_text=" directive::"`` and we were done.

        However with domain support, we introduced the possibility of a ``:`` character
        in the name of a directive. You can imagine a scenario where a user types in a
        domain namespace, say ``py:`` in order to filter down the list of options to
        directives that belong to that namespace. With ``:`` being a trigger character
        for role completions and the like, this would cause editors like VSCode to issue
        a new completion request ignoring the old one.

        That isn't necessarily the end of the world, but with CompletionItems assuming
        that they were following the ``..`` characters, the ``insert_text`` was no
        longer correct leading to broken completions like ``..py: py:function::``.

        In order to handle the two scenarios, conceptually the easiest approach is to
        switch to using a ``text_edit`` and replace the entire line with the correct
        text. Unfortunately in practice this was rather fiddly.

        Upon first setting the ``text_edit`` field VSCode suddenly stopped presenting
        any options! After much debugging, head scratching and searching, I eventually
        found a `couple <https://github.com/microsoft/vscode/issues/38982>`_ of
        `issues <https://github.com/microsoft/vscode/issues/41208>`_ that hinted as to
        what was happening.

        I **think** what happens is that since the ``range`` of the text edit extends
        back to the start of the line VSCode considers the entire line to be the filter
        for the CompletionItems so it's looking to select items that start with ``..``
        - which is none of them!

        To work around this, we additionaly need to set the ``filter_text`` field so
        that VSCode computes matches against that instead of the label. Then in order
        for the items to be shown the value of that field needs to be ``..my:directive``
        so it corresponds with what the user has actually written.

        Parameters
        ----------
        name:
           The name of the directive as a user would type in an reStructuredText
           document
        directive:
           The class definition that implements the Directive's behavior
        match:
           The regular expression match object that represents the line we are providing
           the autocomplete suggestions for.
        position:
           The position in the source code where the autocompletion request was sent
           from.
        """
        groups = match.groupdict()
        prefix = groups["prefix"]
        indent = groups["indent"]

        documentation = inspect.getdoc(directive)

        # Ignore directives that do not provide their own documentation.
        if documentation.startswith(
                "Base class for reStructedText directives."):
            documentation = None

        # TODO: Give better names to arguments based on what they represent.
        args = " ".join("${{{0}:arg{0}}}".format(i)
                        for i in range(1, directive.required_arguments + 1))

        return CompletionItem(
            name,
            kind=CompletionItemKind.Class,
            detail="directive",
            documentation=documentation,
            filter_text=f"..{prefix}{name}",
            insert_text_format=InsertTextFormat.Snippet,
            text_edit=TextEdit(
                range=Range(
                    Position(position.line, 0),
                    Position(position.line, position.character - 1),
                ),
                new_text=f"{indent}.. {name}:: {args}",
            ),
        )
Ejemplo n.º 9
0
def make_keyword_completion_item(word):
    """Return a LSP::CompletionItem for reserved keyword WORD."""
    return CompletionItem(word, CompletionItemKind.Keyword)
Ejemplo n.º 10
0
def make_builtin_completion_item(word):
    return CompletionItem(word, CompletionItemKind.Function)
Ejemplo n.º 11
0
def make_external_completion_item(word):
    """Return a LSP::CompletionItem for function name WORD."""

    return CompletionItem(word, CompletionItemKind.Module)
Ejemplo n.º 12
0
def make_variable_completion_item(word):
    """Return a LSP::CompletionItem for variable name WORD."""
    return CompletionItem(word, CompletionItemKind.Variable)
Ejemplo n.º 13
0
def _complete(english_server, params):
    results = ["what", "no"]
    return CompletionList(False, [CompletionItem(i) for i in results])
Ejemplo n.º 14
0
        def completions(params: CompletionParams):
            if (
                hasattr(params, "context")
                and params.context.triggerKind == CompletionTriggerKind.TriggerCharacter
            ):
                token = ""
                trigger = params.context.triggerCharacter
            else:
                line = self._cursor_line(params.textDocument.uri, params.position)
                idx = params.position.character - 1
                if 0 <= idx < len(line) and line[idx] in trigger_characters:
                    token = ""
                    trigger = line[idx]
                else:
                    word = self._cursor_word(
                        params.textDocument.uri, params.position, False
                    )
                    token = "" if word is None else word[0]
                    trigger = None

            items: List[CompletionItem] = []

            if trigger is None:
                commands = self._api.search_command(token)
                items.extend(
                    CompletionItem(
                        x,
                        CompletionItemKind.Function,
                        documentation=self._api.get_command_doc(x),
                        insert_text=x,
                    )
                    for x in commands
                )

            if trigger is None or trigger == "{":
                variables = self._api.search_variable(token)
                items.extend(
                    CompletionItem(
                        x,
                        CompletionItemKind.Variable,
                        documentation=self._api.get_variable_doc(x),
                        insert_text=x,
                    )
                    for x in variables
                )

            if trigger is None:
                targets = self._api.search_target(token)
                items.extend(
                    CompletionItem(x, CompletionItemKind.Class, insert_text=x)
                    for x in targets
                )

            if trigger == "(":
                func = self._cursor_function(params.textDocument.uri, params.position)
                if func is not None:
                    func = func.lower()
                    if func == "include":
                        modules = self._api.search_module(token, False)
                        items.extend(
                            CompletionItem(
                                x,
                                CompletionItemKind.Module,
                                documentation=self._api.get_module_doc(x, False),
                                insert_text=x,
                            )
                            for x in modules
                        )
                    elif func == "find_package":
                        modules = self._api.search_module(token, True)
                        items.extend(
                            CompletionItem(
                                x,
                                CompletionItemKind.Module,
                                documentation=self._api.get_module_doc(x, True),
                                insert_text=x,
                            )
                            for x in modules
                        )

            return CompletionList(False, items)
Ejemplo n.º 15
0
def completions(ls, params: CompletionParams = None):
    print('start')
    ls.show_message('Validating ' + str(params.position.character))
    if params.position.character < 3:
        print('end')
        return
    document = ls.workspace.get_document(params.textDocument.uri)
    lines = document.lines
    line = lines[params.position.line]
    idx = line.rfind('[ch', 0, params.position.character)
    #print(line)
    if idx == -1:
        print('end')
        return
    next_char = ''
    if params.position.character + 1 < len(line):
        next_char = line[params.position.character + 1]
    if next_char != ']':
        next_char = ']'
    else:
        next_char = ''
    in_list = False
    list_head = line[:idx]
    line = line[idx:params.position.character]
    list_bullet = list_head.replace(' ', '')
    list_stories = []
    first_list_head = list_head
    insert_epic_after = -1
    if list_bullet in ['*', '-']:
        in_list = True

        def extract_id(search_line: str):
            line = search_line[1:]  # trim the bullet
            if not line.startswith('[ch'):
                return None
            line = line[3:]  # Skip `[ch`
            idx = line.find(']')
            if idx == -1:
                return None
            line = line[:idx]
            try:
                return int(line)
            except:
                return None

        first_line = params.position.line
        search_line = lines[first_line].replace(' ', '')
        while first_line > 0 and search_line.startswith(list_bullet):
            first_line -= 1
            search_line = lines[first_line].replace(' ', '')
            story_id = extract_id(search_line)
            if story_id != None:
                list_stories.append(story_id)
        first_line += 1
        first_list_head = lines[first_line]
        idx = first_list_head.find('[')
        first_list_head = first_list_head[:idx]

        insert_epic_after = first_line
        last_line = params.position.line
        search_line = lines[last_line].replace(' ', '')
        while last_line + 1 < len(lines) and search_line.replace(
                ' ', '').startswith(list_bullet):
            last_line += 1
            search_line = lines[last_line].replace(' ', '')
            story_id = extract_id(search_line)
            if story_id != None:
                list_stories.append(story_id)

    if line.find(']') != -1:
        print('end')
        return
    line = line[3:]

    print(line)

    items = []
    prec = math.ceil(math.log10(max_story_position))
    sort_str = '{}:0{}d{}'.format('{', prec, '}')
    ordering = 0

    prefix = '{}'.format(line)
    try:
        id = int(line)
    except:
        prefix = ''

    comp_items = []
    for item in all_stories:
        story = item['story']
        if prefix != '':
            if not str(story['id']).startswith(prefix):
                continue

        tag = 'ch{}'.format(story["id"])
        label = tag
        detail = tag + ': '
        if item['is_namesake']:
            detail += 'Epic: '
        detail += story["name"]
        cap = 94
        sort_text = ''

        def sort_conf(is_higher_prio):
            if is_higher_prio:
                return '('
            return '['

        sort_text += sort_conf(item['main_workflow'])
        sort_text += sort_conf(item['in_progress'])
        sort_text += sort_conf(item['is_mine'])
        sort_text += sort_str.format(story['position'])
        insert_text = tag + next_char
        epic_insert = []
        kind = 'enumMember'
        if in_list:
            insert_text += ' '
            if item['is_namesake']:
                insert_text += 'Epic: '
                kind = 'enum'
            insert_text += story['name'] + '\n' + list_head
            if story['epic_id'] is not None and not item['is_namesake']:
                namesake = epic_by_id[story['epic_id']]['namesake']
                if namesake is not None and namesake['id'] not in list_stories:
                    pos = Position(insert_epic_after, 0)
                    epic_text = '{}[ch{}] Epic: {}\n'.format(
                        first_list_head, namesake['id'], namesake['name'])
                    epic_insert = [TextEdit(Range(pos, pos), epic_text)]

        if len(detail) > cap:
            detail = detail[:cap - 3] + '...'

        comp_items.append(
            CompletionItem(label=detail,
                           sort_text=sort_text,
                           insert_text=insert_text,
                           additional_text_edits=epic_insert,
                           kind=kind))

    print('end')
    return CompletionList(False, comp_items)
Ejemplo n.º 16
0
 def project_to_completion_item(self, project: str) -> CompletionItem:
     return CompletionItem(project,
                           detail="intersphinx",
                           kind=CompletionItemKind.Module)