private def appendDescriptors()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/folding/ScalaFoldingBuilder.scala [46:181]


  private def appendDescriptors(node: ASTNode,
                                document: Document,
                                descriptors: java.util.List[FoldingDescriptor],
                                processedComments: mutable.HashSet[PsiElement],
                                processedRegions: mutable.HashSet[PsiElement]): Unit = {
    val nodeTextRange = node.getTextRange
    if (nodeTextRange.getStartOffset + 1 >= nodeTextRange.getEndOffset) return

    val psi = node.getPsi
    if (isMultiline(node) || isMultilineImport(node) || isNonEmptyExtensionBodyOnNewLine(node)) {
      node.getElementType match {
        case ScalaTokenTypes.tBLOCK_COMMENT |  ScalaDocElementTypes.SCALA_DOC_COMMENT =>
          descriptors add new FoldingDescriptor(node, nodeTextRange)
        case EXTENSION_BODY =>
          // extensions template body do not support `:` in the beginning,
          // we should capture new line before
          val isExtensionsTemplateBody = node.getTreeParent.getElementType == ScalaElementType.EXTENSION
          val range = if (isExtensionsTemplateBody) captureWhitespaceBefore(node, nodeTextRange) else nodeTextRange
          descriptors.add(new FoldingDescriptor(node, range))
        case TEMPLATE_BODY => descriptors.add(new FoldingDescriptor(node, nodeTextRange))
        case ImportStatement if isGoodImport(node) =>
          descriptors add new FoldingDescriptor(node,
            new TextRange(nodeTextRange.getStartOffset + IMPORT_KEYWORD.length + 1, getImportEnd(node)))
        case MatchExprOrMatchType() =>
          val infoOpt = multilineBodyInMatch(node)
          infoOpt.foreach { info =>
            descriptors add new FoldingDescriptor(node, info.range)
          }
        case _ =>
      }

      psi match {
        case p: ScPackaging  =>
          p.findExplicitMarker match {
            case Some(marker) => // `{` or `:`
              val start = nodeTextRange.getStartOffset + marker.getStartOffsetInParent
              val end = nodeTextRange.getEndOffset
              val range = new TextRange(start, end)
              descriptors.add(new FoldingDescriptor(node, range))
            case _ =>
          }
        case p: ScStringLiteral if p.isMultiLineString =>
          descriptors add new FoldingDescriptor(node, nodeTextRange)
        case args: ScArgumentExprList if args.isArgsInParens =>
          descriptors add new FoldingDescriptor(node, nodeTextRange)
        case definition: ScDefinitionWithAssignment =>
          val bodyOpt = definitionBody(definition)
          bodyOpt.foreach { body =>
            val start =
              if (body.startsFromNewLine()) definition.assignment.map(_.endOffset).getOrElse(body.startOffset)
              else body.startOffset
            val end = definition.endOffset // will automatically include end marker
            val rangeNew = TextRange.create(start, end)
            // we generally do not expect bodies empty, but adding this `isEmpty` check just in case
            if (!rangeNew.isEmpty) {
              descriptors.add(new FoldingDescriptor(definition, rangeNew))
            }
          }
        case _ =>
      }

      val treeParent: ASTNode = node.getTreeParent
      if (treeParent != null) {
        psi match {
          case block: ScBlockExpr =>
            // definition with assignment block is attached to the definition itself and is already handled
            if (foldingSettings.isFoldingForAllBlocks && !treeParent.getPsi.is[ScDefinitionWithAssignment]) {
              val rangeNew = elementRangeWithEndMarkerAttached(block, nodeTextRange)
              descriptors.add(new FoldingDescriptor(node, rangeNew))
            }
            else treeParent.getPsi match {
              case _: ScArgumentExprList | _: ScFor | _: ScWhile | _: ScDo | _: ScIf =>
                val rangeNew = elementRangeWithEndMarkerAttached(block, nodeTextRange)
                descriptors.add(new FoldingDescriptor(node, rangeNew))
              case inf: ScInfixExpr if inf.right == node.getPsi => // SCL-3464
                descriptors.add(new FoldingDescriptor(node, nodeTextRange))
              case _ =>
            }
          case _: ScBlock =>
            treeParent.getPsi match {
              // NOTE: it's actually the only possible left variant: case clause,
              // it will be merged with the pattern match above after ScBlockImpl is removed
              case _: ScCaseClause =>
                descriptors.add(new FoldingDescriptor(node, nodeTextRange))
              case _ =>
            }
          case _ =>
        }
      }
    } else if (node.getElementType == TYPE_PROJECTION) {
      node.getPsi match {
        case TypeLambda(typeName, typeParamClause, aliasedType) =>
          val group = FoldingGroup.newGroup("typelambda")
          val range1 = new TextRange(nodeTextRange.getStartOffset, typeParamClause.getTextRange.getStartOffset)
          val d1 = new FoldingDescriptor(node, range1, group) {
            override def getPlaceholderText: String = typeName
          }
          val range2 = new TextRange(aliasedType.getTextRange.getEndOffset, nodeTextRange.getEndOffset)
          val d2 = new FoldingDescriptor(aliasedType.getNode, range2, group) {
            override def getPlaceholderText = ""
          }
          descriptors addAll Seq(d1, d2).asJavaCollection
        case _ =>
      }
    } else if (node.getElementType == ScalaTokenTypes.tLINE_COMMENT) {
      if (!CustomFoldingBuilder.isCustomRegionElement(node.getPsi)) {
        addCommentFolds(node.getPsi.asInstanceOf[PsiComment], processedComments, descriptors)
      }
    } else if (node.getElementType == SIMPLE_TYPE && node.getText == "Unit" &&
      node.getPsi.getParent.is[ScFunctionDefinition] &&
      ScalaCodeStyleSettings.getInstance(node.getPsi.getProject).ENFORCE_FUNCTIONAL_SYNTAX_FOR_UNIT && foldingSettings.isCollapseCustomRegions) {

      node.getPsi match {
        case sc: ScalaPsiElement =>
          (sc.getPrevSiblingNotWhitespace, sc.getNextSiblingNotWhitespace) match {
            case (a1: PsiElement, a2: PsiElement)
              if a1.getNode.getElementType == ScalaTokenTypes.tCOLON && a2.getNode.getElementType == ScalaTokenTypes.tASSIGN =>
              val startElement =
                if (a1.getPrevSibling.is[PsiWhiteSpace]) a1.getPrevSibling
                else a1
              val endElement =
                if (a2.getNextSibling.is[PsiWhiteSpace]) a2.getNextSibling
                else a2
              descriptors add new FoldingDescriptor(node,
                new TextRange(startElement.getTextRange.getStartOffset, endElement.getTextRange.getEndOffset))
              return
            case _ =>
          }
        case _ =>
      }
    }

    for (child <- node.getChildren(null)) {
      appendDescriptors(child, document, descriptors, processedComments, processedRegions)
    }
  }