otNull
  private static HtmlChunk describeDecorator(@NotNull PyDecorator decorator) {
    final HtmlBuilder result = new HtmlBuilder();
    result.append(styledSpan("@" + PyUtil.getReadableRepr(decorator.getCallee(), false), PyHighlighter.PY_DECORATOR));

    final PyArgumentList argumentList = decorator.getArgumentList();
    if (argumentList != null) {
      result.append(styledSpan("(", PyHighlighter.PY_PARENTHS));
      final PyExpression[] argumentsExpressions = argumentList.getArguments();

      final HtmlChunk styledArgumentsList =
        StreamEx
          .of(argumentsExpressions)
          .map(argExpression -> {
            if (!(argExpression instanceof PyKeywordArgument keywordArg)) {
              return highlightExpressionText(argExpression.getText(), argExpression);
            }
            final String argName = argExpression.getName();
            if (argName == null) return null;
            final PyExpression argValueExpression = keywordArg.getValueExpression();
            if (argValueExpression == null) return null;
            return new HtmlBuilder().append(styledSpan(argName, PyHighlighter.PY_KEYWORD_ARGUMENT))
              .append(styledSpan("=", PyHighlighter.PY_OPERATION_SIGN))
              .append(highlightExpressionText(argValueExpression.getText(), argValueExpression))
              .toFragment();
          })
          .nonNull()
          .collect(HtmlChunk.toFragment(styledSpan(", ", PyHighlighter.PY_COMMA)));

      result.append(styledArgumentsList);
      result.append(styledSpan(")", PyHighlighter.PY_PARENTHS));
    }
    return result.toFragment();
  }


otNull
  private static HtmlChunk describeDecorator(@NotNull PyDecorator decorator) {