Skip to content

Commit

Permalink
Yaml: YamlScalarTextEvaluator extracted to implement old `getTextVa…
Browse files Browse the repository at this point in the history
…lue` behavior

GitOrigin-RevId: 0dfa545f3b9d3c8a46452a7dd3a657e618d3b1f6
  • Loading branch information
xiexed authored and intellij-monorepo-bot committed May 11, 2021
1 parent ea64123 commit dc61aef
Show file tree
Hide file tree
Showing 37 changed files with 727 additions and 682 deletions.
5 changes: 0 additions & 5 deletions plugins/yaml/src/org/jetbrains/yaml/psi/YAMLBlockScalar.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,4 @@

/** See <a href="http://www.yaml.org/spec/1.2/spec.html#id2793652">8.1. Block Scalar Styles</a> */
public interface YAMLBlockScalar extends YAMLScalar {
/** It is temporary solution. Please Do not use it in production! */
@ApiStatus.Internal
Key<Boolean> FORCE_KEEP_CHOMPING = new Key<>("Force keep chomping indicator");

boolean hasExplicitIndent();
}
228 changes: 0 additions & 228 deletions plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockScalarImpl.java

This file was deleted.

151 changes: 151 additions & 0 deletions plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockScalarImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.jetbrains.yaml.psi.impl

import com.intellij.lang.ASTNode
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.tailOrEmpty
import com.intellij.util.text.splitLineRanges
import org.jetbrains.yaml.YAMLElementTypes
import org.jetbrains.yaml.YAMLTokenTypes
import org.jetbrains.yaml.YAMLUtil
import org.jetbrains.yaml.psi.YAMLBlockScalar

abstract class YAMLBlockScalarImpl(node: ASTNode) : YAMLScalarImpl(node), YAMLBlockScalar {
protected abstract val contentType: IElementType

override fun isMultiline(): Boolean = true

override fun getContentRanges(): List<TextRange> {

return CachedValuesManager.getCachedValue(this, CachedValueProvider {
val myStart = textRange.startOffset
val indent = locateIndent()

val contentRanges = linesNodes.mapNotNull { line ->
val first = line.first()
TextRange.create(first.textRange.startOffset - myStart
+ (if (first.elementType == YAMLTokenTypes.INDENT) indent else 0),
line.last().textRange.endOffset - myStart)
}

CachedValueProvider.Result.create((if (contentRanges.size == 1)
listOf(contentRanges.single().let { TextRange.create(it.endOffset, it.endOffset) })
else if (contentRanges.isEmpty())
emptyList()
else
contentRanges.tailOrEmpty()), PsiModificationTracker.MODIFICATION_COUNT)
})
}

fun hasExplicitIndent(): Boolean = explicitIndent != IMPLICIT_INDENT

/**
* @return Nth child of this scalar block item type ([YAMLElementTypes.BLOCK_SCALAR_ITEMS]).
* Child with number 0 is a header. Content children have numbers more than 0.
*/
fun getNthContentTypeChild(nth: Int): ASTNode? {
var number = 0
var child = node.firstChildNode
while (child != null) {
if (child.elementType === contentType) {
if (number == nth) {
return child
}
number++
}
child = child.treeNext
}
return null
}

/** See [8.1.1.1. Block Indentation Indicator](http://www.yaml.org/spec/1.2/spec.html#id2793979) */
fun locateIndent(): Int {
val indent = explicitIndent
if (indent != IMPLICIT_INDENT) {
return indent
}
val firstLine = getNthContentTypeChild(1)
if (firstLine != null) {
return YAMLUtil.getIndentInThisLine(firstLine.psi)
}
else {
val line = linesNodes.getOrNull(1)
if (line != null) {
val lineIndentElement = ContainerUtil.find(line) { l: ASTNode -> l.elementType == YAMLTokenTypes.INDENT }
if (lineIndentElement != null) {
return lineIndentElement.textLength
}
}
}
return 0
}

@Throws(IllegalArgumentException::class)
override fun getEncodeReplacements(input: CharSequence): List<Pair<TextRange, String>> {
var indent = locateIndent()
if (indent == 0) {
indent = YAMLUtil.getIndentToThisElement(this) + DEFAULT_CONTENT_INDENT
}
val indentString = StringUtil.repeatSymbol(' ', indent)

return splitLineRanges(input).zipWithNext { a, b -> Pair.create(TextRange.create(a.endOffset, b.startOffset), indentString) }.toList()
}

protected val linesNodes: List<List<ASTNode>>
get() {
val result: MutableList<List<ASTNode>> = SmartList()
var currentLine: MutableList<ASTNode> = SmartList()
var child = node.firstChildNode
while (child != null) {
currentLine.add(child)
if (isEol(child)) {
result.add(currentLine)
currentLine = SmartList()
}
child = child.treeNext
}
if (!currentLine.isEmpty()) {
result.add(currentLine)
}
return result
}

// YAML 1.2 standard does not allow more then 1 symbol in indentation number
private val explicitIndent: Int
get() {
val headerNode = getNthContentTypeChild(0)!!
val header = headerNode.text
for (i in 0 until header.length) {
if (Character.isDigit(header[i])) {
val k = i + 1
// YAML 1.2 standard does not allow more then 1 symbol in indentation number
if (k < header.length && Character.isDigit(header[k])) {
return IMPLICIT_INDENT
}
val res = header.substring(i, k).toInt()
return if (res == 0) {
// zero is not allowed as c-indentation-indicator
IMPLICIT_INDENT
}
else res
}
}
return IMPLICIT_INDENT
}

}

const val DEFAULT_CONTENT_INDENT = 2
private const val IMPLICIT_INDENT = -1

fun isEol(node: ASTNode?): Boolean = when (node) {
null -> false
else -> YAMLElementTypes.EOL_ELEMENTS.contains(node.elementType)
}
Loading

0 comments on commit dc61aef

Please sign in to comment.