List<CompletionItem> getFunctionPropertyCompletion(EventCompletionContext context, Node startOfWordNode) {
        if (context.triggerCharacter != '.') return List.of();
        Node rawNode = CSTUtils.findASTClassAncestor(startOfWordNode, feature.class);
        if (rawNode == null || rawNode.size() == 0 || !rawNode.isSchemaNode()) {
            return List.of();
        }
        SchemaNode featureNode = rawNode.getSchemaNode();
        if (featureNode.getRankNode().isEmpty()) {
            return List.of();
        }

        RankNode rankNode = featureNode.getRankNode().get();

        Optional<SpecificFunction> functionSignature = rankNode.getFunctionSignature();
        if (functionSignature.isEmpty()) {
            return List.of();
        }

        SpecificFunction specificFunction = functionSignature.get();
        FunctionSignature signature = functionSignature.get().getSignature();

        List<CompletionItem> result = new ArrayList<>();

        for (String prop : signature.getProperties()) {
            if (prop.isBlank()) continue;
            CompletionItem item = CompletionUtils.constructBasic(prop);

            specificFunction.setProperty(prop);

            Optional<Hover> documentationHover = SchemaHover.getRankFeatureHover(specificFunction);

            if (documentationHover.isPresent() && documentationHover.get().getContents().isRight()) {
                item.setDocumentation(documentationHover.get().getContents().getRight());
            }

            result.add(item);

        }
        return result;
    }
Compute completion snippets for all the builtin ranking features using the signatures
in {@link BuiltInFunctions}.
integration/schema-language-server/language-server/src/main/java/ai/vespa/schemals/lsp/schema/completion/provider/RankingExpressionCompletion.java