Beispiel #1
0
def complete(completion_context):
    """
    :param CompletionContext completion_context:
    """
    from robocorp_ls_core.lsp import CompletionItemKind
    from robocorp_ls_core.lsp import CompletionItem
    from robocorp_ls_core.lsp import TextEdit
    from robocorp_ls_core.lsp import Range
    from robocorp_ls_core.lsp import Position
    from robotframework_ls.impl import text_utilities
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM, )
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL, )

    selection = completion_context.sel  #: :type selection: DocumentSelection
    line_start = selection.line_to_column
    items = []

    if line_start:
        tu = text_utilities.TextUtilities(line_start)

        if tu.strip_leading_chars("*"):  # i.e.: the line must start with '*'
            tu.strip()

            words = completion_context.get_accepted_section_header_words()
            config = completion_context.config

            form = config.get_setting(
                OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM,
                str,
                OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL,
            )
            matcher = RobotStringMatcher(tu.text)
            for word in words:
                if form == "plural":
                    if not word.endswith("s"):
                        continue
                elif form == "singular":
                    if word.endswith("s"):
                        continue
                if matcher.accepts(word):
                    label = "*** %s ***" % (word, )
                    text_edit = TextEdit(
                        Range(
                            # i.e.: always replace from the start of the line.
                            start=Position(selection.line, 0),
                            end=Position(selection.line, selection.col),
                        ),
                        label,
                    )
                    # text_edit = None
                    items.append(
                        CompletionItem(label,
                                       kind=CompletionItemKind.Class,
                                       text_edit=text_edit,
                                       insertText=text_edit.newText))

    return [item.to_dict() for item in items]
Beispiel #2
0
    def __init__(self, match_name):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )

        self.match_name = match_name
        self.matches = []

        self._matcher = RobotStringMatcher(match_name)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            match_name)
    def __init__(self, selection, token):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )

        token_str = token.value

        self.completion_items = []
        self.selection = selection
        self.token = token

        self._matcher = RobotStringMatcher(token_str)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            token_str)
Beispiel #4
0
class _FindDefinitionKeywordCollector(IDefinitionsCollector):
    def __init__(self, match_name):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )

        self.match_name = match_name
        self.matches = []

        self._matcher = RobotStringMatcher(match_name)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            match_name)

    def accepts(self, keyword_name):
        return True

    def on_keyword(self, keyword_found):
        if any(x.keyword_name == keyword_found.keyword_name
               for x in self.matches):
            return

        if self._matcher.is_keyword_name_match(keyword_found.keyword_name):
            definition = _DefinitionFromKeyword(keyword_found)
            self.matches.append(definition)
            return

        for matcher in self._scope_matchers:
            if matcher.is_keyword_match(keyword_found):
                definition = _DefinitionFromKeyword(keyword_found)
                self.matches.append(definition)
                return
Beispiel #5
0
    def __init__(
        self,
        selection,
        token,
        import_location_info: "_ImportLocationInfo",
        imported_keyword_name_to_keyword: Dict[str, List[IKeywordFound]],
    ):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher

        token_str = token.value

        self.completion_items: List[dict] = []
        self.selection = selection
        self.import_location_info = import_location_info
        self.token = token
        self.imported_keyword_name_to_keyword = imported_keyword_name_to_keyword

        self._matcher = RobotStringMatcher(token_str)
def find_definition(completion_context):
    """
    :param CompletionContext completion_context:
    :rtype: list(IDefinition)
    
    :note:
        Definitions may be found even if a given source file no longer exists
        at this place (callers are responsible for validating entries).
    """
    from robotframework_ls.impl import ast_utils
    from robotframework_ls.impl.collect_keywords import collect_keywords
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robotframework_ls.impl.variable_completions import collect_variables

    token_info = completion_context.get_current_token()
    if token_info is not None:
        token = ast_utils.get_keyword_name_token(token_info.node,
                                                 token_info.token)
        if token is not None:
            collector = _FindDefinitionKeywordCollector(token.value)
            collect_keywords(completion_context, collector)
            return collector.matches

        token = ast_utils.get_library_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            libspec_manager = completion_context.workspace.libspec_manager
            library_doc = libspec_manager.get_library_info(
                token.value,
                create=True,
                current_doc_uri=completion_context.doc.uri)
            if library_doc is not None:
                definition = _DefinitionFromLibrary(library_doc)
                return [definition]

        token = ast_utils.get_resource_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            resource_import_as_doc = completion_context.get_resource_import_as_doc(
                token_info.node)
            if resource_import_as_doc is not None:
                return [_DefinitionFromResource(resource_import_as_doc)]

    token_info = completion_context.get_current_variable()
    if token_info is not None:

        token = token_info.token
        value = token.value

        collector = _FindDefinitionVariablesCollector(
            completion_context.sel, token, RobotStringMatcher(value))
        collect_variables(completion_context, collector)
        return collector.matches

    return []
Beispiel #7
0
    def __init__(self, completion_context: ICompletionContext, token):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )
        from robotframework_ls.robot_config import create_convert_keyword_format_func

        token_str = token.value

        self.completion_items: List[dict] = []
        self.completion_context = completion_context
        self.selection = completion_context.sel
        self.token = token

        self._matcher = RobotStringMatcher(token_str)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            token_str)
        config = completion_context.config

        self._convert_keyword_format = create_convert_keyword_format_func(
            config)
def complete(completion_context):
    """
    :param CompletionContext completion_context:
    """
    from robotframework_ls.impl.string_matcher import RobotStringMatcher

    token_info = completion_context.get_current_variable()
    if token_info is not None:
        token = token_info.token
        value = token.value
        if value.endswith("}"):
            value = value[:-1]
        collector = _Collector(completion_context.sel, token, RobotStringMatcher(value))
        collect_variables(completion_context, collector)
        return collector.completion_items
    return []
class _Collector(object):
    def __init__(self, selection, token):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )

        token_str = token.value

        self.completion_items = []
        self.selection = selection
        self.token = token

        self._matcher = RobotStringMatcher(token_str)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            token_str)

    def accepts(self, keyword_name):
        if self._matcher.accepts_keyword_name(keyword_name):
            return True
        for matcher in self._scope_matchers:
            if matcher.accepts_keyword_name(keyword_name):
                return True
        return False

    def _create_completion_item_from_keyword(self,
                                             keyword_found,
                                             selection,
                                             token,
                                             col_delta=0):
        """
        :param IKeywordFound keyword_found:
        :param selection:
        :param token:
        """
        from robotframework_ls.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robotframework_ls.lsp import MarkupKind

        label = keyword_found.keyword_name
        text = label

        for i, arg in enumerate(keyword_found.keyword_args):
            arg = arg.replace("$", "\\$").replace("{", "").replace("}", "")
            if arg.startswith("**"):
                arg = "&" + arg[2:]

            elif arg.startswith("*"):
                arg = "@" + arg[1:]

            text += "    ${%s:%s}" % (i + 1, arg)

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset + col_delta),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            keyword_found.keyword_name,
            kind=keyword_found.completion_item_kind,
            text_edit=text_edit,
            documentation=keyword_found.docs,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=(MarkupKind.Markdown
                                 if keyword_found.docs_format == "markdown"
                                 else MarkupKind.PlainText),
        ).to_dict()

    def on_keyword(self, keyword_found):
        col_delta = 0
        if not self._matcher.accepts_keyword_name(keyword_found.keyword_name):
            for matcher in self._scope_matchers:
                if matcher.accepts_keyword(keyword_found):
                    # +1 for the dot
                    col_delta = len(matcher.resource_or_library_name) + 1
                    break
            else:
                return  # i.e.: don't add completion

        item = self._create_completion_item_from_keyword(keyword_found,
                                                         self.selection,
                                                         self.token,
                                                         col_delta=col_delta)

        self.completion_items.append(item)
Beispiel #10
0
class _Collector(object):
    def __init__(
        self,
        selection,
        token,
        import_location_info: "_ImportLocationInfo",
        imported_keyword_name_to_keyword: Dict[str, List[IKeywordFound]],
    ):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher

        token_str = token.value

        self.completion_items: List[dict] = []
        self.selection = selection
        self.import_location_info = import_location_info
        self.token = token
        self.imported_keyword_name_to_keyword = imported_keyword_name_to_keyword

        self._matcher = RobotStringMatcher(token_str)

    def accepts(self, symbols_entry):
        keyword_name = symbols_entry["name"]
        if not self._matcher.accepts_keyword_name(keyword_name):
            return False

        keywords_found: List[
            IKeywordFound] = self.imported_keyword_name_to_keyword.get(
                keyword_name)
        if not keywords_found:
            return True

        # No longer do this check: if there's some symbol imported already, don't
        # try to match with the filename (just don't show it).
        #
        # This change was done because the check below wasn't perfect
        # and because it can be a bit confusing since everything imported
        # works as a wild import in RobotFramework (so, even if it was a different
        # keyword from a different place, importing it would make it clash and
        # thus such a completion is kind of strange).
        #
        # for keyword_found in keywords_found:
        #     if (
        #         uris.from_fs_path(keyword_found.source)
        #         == symbols_entry["location"]["uri"]
        #     ):
        #         return False
        # return True

        return False

    def create_completion_item(
        self,
        completion_context: ICompletionContext,
        keyword_name,
        selection,
        token,
        col_delta: int,
        memo: Set[str],
        lib_import: Optional[str] = None,
        resource_path: Optional[str] = None,
        data: Optional[Any] = None,
    ) -> None:
        """
        Note: the lib_import and resource_path are the strings to be added
        so that the given library/resource is loaded.
        
        i.e.: It's the name concatenated to the `Library    {lib_import}` or
        `Resource    {resource_path}`.
        """
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.protocols import CompletionType

        label = f"{keyword_name} ({lib_import or resource_path})"
        if label in memo:
            return
        memo.add(label)

        prefix = ""
        import_line = -1
        if completion_context.type != CompletionType.shell:
            if lib_import is not None:
                import_line = self.import_location_info.get_library_import_line(
                )
            elif resource_path is not None:
                import_line = self.import_location_info.get_resource_import_line(
                )

        if import_line == -1:
            # There's no existing import, so, let's see if we have a *** Settings *** section.
            # If we don't we have to create the whole settings, otherwise, we'll add the statement
            # as the first thing in the existing *** Settings *** section.
            if completion_context.type == CompletionType.shell:
                import_line = 0
                prefix = "*** Settings ***\n"
            elif self.import_location_info.setting_section_node_info is None:
                import_line = 0
                prefix = "*** Settings ***\n"
            else:
                import_line = (self.import_location_info.
                               setting_section_node_info.node.end_lineno - 1)

        text = keyword_name

        if keyword_name in self.imported_keyword_name_to_keyword:
            check = lib_import or resource_path
            if check:
                basename = os.path.basename(check)
                if basename.endswith((".txt", ".py", ".robot", ".resource")):
                    basename = os.path.splitext(basename)[0]
                text = f"{basename}.{keyword_name}"

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset + col_delta),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        additional_text_edits: List[TextEdit] = []

        if lib_import is not None:
            additional_text_edits.append(
                TextEdit(
                    Range(start=Position(import_line, 0),
                          end=Position(import_line, 0)),
                    f"{prefix}Library    {lib_import}\n",
                ))
        elif resource_path is not None:
            additional_text_edits.append(
                TextEdit(
                    Range(start=Position(import_line, 0),
                          end=Position(import_line, 0)),
                    f"{prefix}Resource    {resource_path}\n",
                ))

        # text_edit = None
        self.completion_items.append(
            CompletionItem(
                label,
                kind=CompletionItemKind.Reference,
                text_edit=text_edit,
                insertText=text_edit.newText,
                documentation="",
                insertTextFormat=InsertTextFormat.Snippet,
                documentationFormat=MarkupKind.PlainText,
                additionalTextEdits=additional_text_edits,
                data=data,
            ).to_dict())
Beispiel #11
0
class _Collector(object):
    def __init__(self, completion_context: ICompletionContext, token):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )
        from robotframework_ls.robot_config import create_convert_keyword_format_func

        token_str = token.value

        self.completion_items: List[dict] = []
        self.completion_context = completion_context
        self.selection = completion_context.sel
        self.token = token

        self._matcher = RobotStringMatcher(token_str)
        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            token_str)
        config = completion_context.config

        self._convert_keyword_format = create_convert_keyword_format_func(
            config)

    def accepts(self, keyword_name):
        if self._matcher.accepts_keyword_name(keyword_name):
            return True
        for matcher in self._scope_matchers:
            if matcher.accepts_keyword_name(keyword_name):
                return True
        return False

    def _create_completion_item_from_keyword(self,
                                             keyword_found: IKeywordFound,
                                             selection,
                                             token,
                                             col_delta=0):
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.protocols import IKeywordArg

        label = keyword_found.keyword_name

        if keyword_found.library_name:
            # If we found the keyword in a library, convert its format depending on
            # the user configuration.
            label = self._convert_keyword_format(label)

        text = label
        arg: IKeywordArg
        for i, arg in enumerate(keyword_found.keyword_args):
            if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None:
                continue

            arg_name = arg.arg_name
            arg_name = arg_name.replace("$",
                                        "\\$").replace("{",
                                                       "").replace("}", "")

            text += "    ${%s:%s}" % (i + 1, arg_name)

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset + col_delta),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            label,
            kind=keyword_found.completion_item_kind,
            text_edit=text_edit,
            insertText=text_edit.newText,
            documentation=keyword_found.docs,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=(MarkupKind.Markdown
                                 if keyword_found.docs_format == "markdown"
                                 else MarkupKind.PlainText),
        ).to_dict()

    def on_keyword(self, keyword_found):
        col_delta = 0
        if not self._matcher.accepts_keyword_name(keyword_found.keyword_name):
            for matcher in self._scope_matchers:
                if matcher.accepts_keyword(keyword_found):
                    # +1 for the dot
                    col_delta = len(matcher.resource_or_library_name) + 1
                    break
            else:
                return  # i.e.: don't add completion

        item = self._create_completion_item_from_keyword(keyword_found,
                                                         self.selection,
                                                         self.token,
                                                         col_delta=col_delta)

        self.completion_items.append(item)
Beispiel #12
0
def complete(completion_context):
    """
    :param CompletionContext completion_context:
    """
    import itertools
    from robocorp_ls_core.lsp import (
        TextEdit,
        Range,
        Position,
        CompletionItem,
        CompletionItemKind,
    )

    section_name = completion_context.get_current_section_name()
    if section_name:
        from robotframework_ls.impl.string_matcher import RobotStringMatcher

        section = completion_context.get_section(section_name)
        if section is not None:
            selection = completion_context.sel  #: :type selection: DocumentSelection
            line_to_col = selection.line_to_column
            if line_to_col.endswith("  "):
                return []
            replace_to_col = selection.col
            if section.names_in_brackets:
                for i, c in enumerate(line_to_col):
                    if c.isspace():
                        continue
                    elif c == "[":
                        line_to_col = line_to_col[i + 1:]
                        replace_from_col = i
                        break
                    else:
                        return []
                else:
                    return []

                matcher = RobotStringMatcher(line_to_col)

            else:
                # i.e.: Needs to be the first char
                matcher = RobotStringMatcher(line_to_col)
                replace_from_col = 0

            ret = []
            for word in sorted(itertools.chain(section.names,
                                               section.aliases)):
                if matcher.accepts(word):
                    if section.names_in_brackets:
                        label = "[%s]" % (word, )
                        line = selection.current_line
                        replacement = "[%s]" % (word, )
                        if line[selection.col:].startswith("]"):
                            replace_to_col += 1

                    else:
                        label = word
                        replacement = word

                    text_edit = TextEdit(
                        Range(
                            start=Position(selection.line, replace_from_col),
                            end=Position(selection.line, replace_to_col),
                        ),
                        replacement,
                    )
                    # text_edit = None
                    ret.append(
                        CompletionItem(label,
                                       kind=CompletionItemKind.Keyword,
                                       text_edit=text_edit).to_dict())

            return ret

    return []
Beispiel #13
0
def _get_completions(completion_context, token, match_libs, extensions,
                     skip_current):
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robocode_ls_core import uris
    from robotframework_ls.impl.robot_constants import BUILTIN_LIB

    ret = []

    sel = completion_context.sel
    value_to_cursor = token.value
    if token.end_col_offset > sel.col:
        value_to_cursor = value_to_cursor[:-(token.end_col_offset - sel.col)]
    if u"{" in value_to_cursor:
        value_to_cursor = completion_context.token_value_resolving_variables(
            value_to_cursor)

    value_to_cursor_split = os.path.split(value_to_cursor)

    if os.path.isabs(value_to_cursor):
        _add_completions_from_dir(
            completion_context,
            value_to_cursor_split[0],
            RobotStringMatcher(value_to_cursor_split[1]),
            ret,
            sel,
            token,
            value_to_cursor_split[1],
            extensions,
            skip_current=skip_current,
        )

    else:
        if match_libs:
            matcher = RobotStringMatcher(value_to_cursor)
            libspec_manager = completion_context.workspace.libspec_manager
            library_names = set(libspec_manager.get_library_names())
            library_names.discard(BUILTIN_LIB)

            for library_name in library_names:
                if matcher.accepts(library_name):
                    ret.append(
                        _create_completion_item(library_name, sel, token))

        # After checking the existing library names in memory (because we
        # loaded them at least once), check libraries in the filesystem.
        uri = completion_context.doc.uri
        path = uris.to_fs_path(uri)
        dirname = os.path.dirname(path)

        matcher = RobotStringMatcher(value_to_cursor_split[1])
        directory = os.path.join(dirname, value_to_cursor_split[0])
        _add_completions_from_dir(
            completion_context,
            directory,
            matcher,
            ret,
            sel,
            token,
            value_to_cursor_split[1],
            extensions,
            skip_current=skip_current,
        )
    return ret
def find_definition(
        completion_context: ICompletionContext) -> Sequence[IDefinition]:
    """
    :note:
        Definitions may be found even if a given source file no longer exists
        at this place (callers are responsible for validating entries).
    """
    from robotframework_ls.impl import ast_utils
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robotframework_ls.impl.variable_completions import collect_variables

    token_info = completion_context.get_current_token()

    if token_info is not None:
        matches = find_keyword_definition(completion_context, token_info)
        if matches is not None:
            return matches

        token = ast_utils.get_library_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            libspec_manager = completion_context.workspace.libspec_manager
            completion_context.check_cancelled()
            library_doc = libspec_manager.get_library_info(
                completion_context.token_value_resolving_variables(token),
                create=True,
                current_doc_uri=completion_context.doc.uri,
            )
            if library_doc is not None:
                definition = _DefinitionFromLibrary(library_doc)
                return [definition]

        token = ast_utils.get_resource_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            completion_context.check_cancelled()
            resource_import_as_doc = completion_context.get_resource_import_as_doc(
                token_info.node)
            if resource_import_as_doc is not None:
                return [_DefinitionFromResource(resource_import_as_doc)]

        token = ast_utils.get_variables_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            completion_context.check_cancelled()
            variable_import_as_doc = completion_context.get_variable_import_as_doc(
                token_info.node)
            if variable_import_as_doc is not None:
                return [_DefinitionFromVariableImport(variable_import_as_doc)]

    token_info = completion_context.get_current_variable()
    if token_info is not None:

        token = token_info.token
        value = token.value
        match = next(iter(_RF_VARIABLE.findall(value)), value)
        collector = _FindDefinitionVariablesCollector(
            completion_context.sel, token, RobotStringMatcher(match))
        collect_variables(completion_context, collector)
        return collector.matches

    return []
class _Collector(object):
    def __init__(self, selection, token):
        from robotframework_ls.impl.string_matcher import RobotStringMatcher
        from robotframework_ls.impl.string_matcher import (
            build_matchers_with_resource_or_library_scope, )

        token_str = token.value if token is not None else None

        self.completion_items = []
        self.selection = selection
        self.token = token

        self._matcher = RobotStringMatcher(
            token_str) if token_str is not None else None

        self._scope_matchers = build_matchers_with_resource_or_library_scope(
            token_str) if token_str is not None else []

    def accepts(self, keyword_name):
        if any(x.label == keyword_name for x in self.completion_items):
            return False

        if self._matcher is None:
            return True

        if self._matcher.accepts_keyword_name(keyword_name):
            return True
        for matcher in self._scope_matchers:
            if matcher.accepts_keyword_name(keyword_name):
                return True

        return False

    def _create_completion_item_from_keyword(self,
                                             keyword_found: IKeywordFound,
                                             selection,
                                             token,
                                             col_delta=0):
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.robot_specbuilder import KeywordArg

        label = keyword_found.keyword_name
        text = label

        arg: KeywordArg
        for i, arg in enumerate(keyword_found.keyword_args):
            if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None:
                continue

            arg_name = arg.arg_name
            arg_name = arg_name.replace("$",
                                        "\\$").replace("{",
                                                       "").replace("}", "")

            text += "    ${%s:%s}" % (i + 1, arg_name)

        text_edit = TextEdit(
            Range(
                start=Position(
                    selection.line, token.col_offset +
                    col_delta if token is not None else selection.col),
                end=Position(
                    selection.line, token.end_col_offset
                    if token is not None else selection.col),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            keyword_found.keyword_name,
            kind=keyword_found.completion_item_kind,
            text_edit=text_edit,
            insertText=text_edit.newText,
            documentation=keyword_found.docs,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=(MarkupKind.Markdown
                                 if keyword_found.docs_format == "markdown"
                                 else MarkupKind.PlainText),
        )

    def on_keyword(self, keyword_found):
        col_delta = 0

        if self._matcher is not None and not self._matcher.accepts_keyword_name(
                keyword_found.keyword_name):
            for matcher in self._scope_matchers:
                if matcher.accepts_keyword(keyword_found):
                    # +1 for the dot
                    col_delta = len(matcher.resource_or_library_name) + 1
                    break
            else:
                return  # i.e.: don't add completion

        item = self._create_completion_item_from_keyword(keyword_found,
                                                         self.selection,
                                                         self.token,
                                                         col_delta=col_delta)

        self.completion_items.append(item)