private Optional<SchemaNode> match(EventCompletionContext context) {
        Position searchPos = context.startOfWord();
        if (searchPos == null)searchPos = context.position;
        Node last = CSTUtils.getLastCleanNode(context.document.getRootNode(), searchPos);
        if (last == null || !last.isSchemaNode()) return Optional.empty();

        if (last.isASTInstance(IDENTIFIER.class))last = last.getParent();
        if (last.isASTInstance(COMMA.class))last = last.getPrevious();


        // Skip previously declared fields in the list
        // to get to the start where we can determine the pattern fields: ...
        while (last != null &&
                (last.isASTInstance(identifierStr.class) || last.isASTInstance(identifierWithDashStr.class)) && 
                (last.getPrevious() != null && last.getPrevious().getSchemaNode().getSchemaType() == TokenType.COMMA)) {
        last = last.getPrevious().getPrevious();
        }

        if (last == null)return Optional.empty();

        searchPos = last.getRange().getStart();

        SchemaNode match = context.document.lexer().matchBackwards(searchPos, 1, false, TokenType.IDENTIFIER, TokenType.INHERITS);

        // edge case for rank profiles.
        if (match != null && match.getParent() != null && match.getParent().getParent() != null && match.getParent().getParent().isASTInstance(identifierWithDashStr.class))
            match = match.getParent().getSchemaNode();

        // Has to be on the same line
        if (match != null && match.getRange().getStart().getLine() == context.position.getLine()
                && match.getParent().hasSymbol()) return Optional.of(match);

        return Optional.empty();
    }
For completing user defined identifiers after "inherits".
integration/schema-language-server/language-server/src/main/java/ai/vespa/schemals/lsp/schema/completion/provider/InheritanceCompletion.java