string stuff cleanup and bugfixes

This commit is contained in:
FalsePattern 2024-10-29 22:48:05 +01:00
parent cd474221a6
commit 431e09830f
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
4 changed files with 67 additions and 65 deletions

View file

@ -1,8 +1,6 @@
package com.falsepattern.zigbrains.zig.intentions
import com.falsepattern.zigbrains.zig.psi.ZigStringLiteral
import com.falsepattern.zigbrains.zig.psi.component1
import com.falsepattern.zigbrains.zig.psi.component2
import com.falsepattern.zigbrains.zig.util.escape
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
import com.intellij.openapi.editor.Editor
@ -29,8 +27,12 @@ class MakeStringQuoted: PsiElementBaseIntentionAction() {
if (!str.isMultiline)
return
val escaper = str.createLiteralTextEscaper()
val (contentStart, contentEnd) = escaper.relevantTextRange
val (fullStart, fullEnd) = str.textRange
val contentRange = escaper.relevantTextRange
val contentStart = contentRange.startOffset
val contentEnd = contentRange.endOffset
val fullRange = str.textRange
val fullStart = fullRange.startOffset
val fullEnd = fullRange.endOffset
var caretOffset = editor.caretModel.offset
val prefix = TextRange(contentStart, max(contentStart, caretOffset - fullStart))
val suffix = TextRange(min(contentEnd, caretOffset - fullStart), contentEnd)

View file

@ -13,48 +13,58 @@ import com.intellij.psi.StringEscapesTokenTypes
import com.intellij.util.MathUtil
import kotlin.math.max
fun getTextRangeBounds(contentRanges: List<TextRange>): TextRange =
if (contentRanges.isEmpty())
TextRange.EMPTY_RANGE
else
TextRange.create(contentRanges.first().startOffset, contentRanges.last().endOffset)
fun CharSequence.getMultiLineContent(startMark: String): List<TextRange> {
fun CharSequence.getMultilineContent(startMark: String): List<TextRange> {
val result = ArrayList<TextRange>()
val textLength = this.length
val markLength = startMark.length
var offset = 0
while (offset < textLength) {
val markIndex = this.indexOf(startMark, offset)
if (markIndex < 0)
break
val stringStart = markIndex + markLength
var found: Int? = null
findEnd@ for (end in stringStart until textLength) {
val cI = this[end]
when (cI) {
'\r' -> {
if (end + 1 < textLength && this[end + 1] == '\n') {
found = end + 2
break@findEnd
}
found = end + 1
break@findEnd
}
'\n' -> {
found = end + 1
break@findEnd
var stringStart = 0
var inBody = false
val textLength = length
val firstChar = startMark[0]
val extraChars = startMark.substring(1)
var i = 0
loop@ while (i < textLength) {
val cI = this[i]
if (!inBody) {
if (cI == firstChar &&
i + extraChars.length < textLength
) {
for (j in extraChars.indices) {
if (this[i + j + 1] != startMark[j]) {
i++
continue@loop
}
}
i += extraChars.length
inBody = true
stringStart = i + 1
}
if (found == null)
break
result.add(TextRange(stringStart, kotlin.math.min(textLength - 1, found)))
offset = found
} else if (cI == '\r') {
if (i + 1 < length && this[i + 1] == '\n') {
i++
}
inBody = false
result.add(
TextRange(
stringStart,
kotlin.math.min((textLength - 1), (i + 1))
)
)
} else if (cI == '\n') {
inBody = false
result.add(
TextRange(
stringStart,
kotlin.math.min((textLength - 1), (i + 1))
)
)
}
i++
}
return result
}
@ -73,7 +83,9 @@ fun splitString(
val token = psiAtOffset.node
val text = document.charsSequence
val (rangeStart, rangeEnd) = token.textRange
val range = token.textRange
val rangeStart = range.startOffset
val rangeEnd = range.endOffset
val lexer = ZigLexerStringAdapter()
lexer.start(text, rangeStart, rangeEnd)
caretOffset = lexer.skipStringLiteralEscapes(caretOffset)
@ -141,12 +153,3 @@ private fun Lexer.skipStringLiteralEscapes(caretOffset: Int): Int {
}
return caretOffset
}
operator fun Segment.component1(): Int {
return startOffset
}
operator fun Segment.component2(): Int {
return endOffset
}

View file

@ -8,7 +8,6 @@ import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.psi.LiteralTextEscaper
import com.intellij.psi.impl.source.tree.LeafElement
import java.lang.StringBuilder
abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(node), ZigStringLiteral {
override fun isValidHost() = true
@ -20,7 +19,7 @@ abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(no
get() = if (!isMultiline) {
listOf(TextRange(1, textLength - 1))
} else {
text.getMultiLineContent("\\\\")
text.getMultilineContent("\\\\")
}
override fun updateText(text: String): ZigStringLiteral {
@ -60,33 +59,30 @@ abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(no
var currentOffsetInDecoded = 0
var last: TextRange? = null
val isMultiline = myHost.isMultiline
for (range in contentRanges) {
for (i in contentRanges.indices) {
val range = rangeInsideHost.intersection(contentRanges[i]) ?: continue
last = range
val (rangeStart, _) = range
val curString = range.substring(text)
val curString = range.subSequence(text)
val replacementsForThisLine = curString.decodeReplacements(isMultiline)
val replacementsForThisLine = curString.decodeReplacements(myHost.isMultiline)
var encodedOffsetInCurrentLine = 0
for ((thisRange, replacement) in replacementsForThisLine) {
val (thisStart, _) = thisRange
val deltaLength = thisStart - encodedOffsetInCurrentLine
for (replacement in replacementsForThisLine) {
val deltaLength = replacement.first.startOffset - encodedOffsetInCurrentLine
val currentOffsetBeforeReplacement = currentOffsetInDecoded + deltaLength
if (currentOffsetBeforeReplacement > offsetInDecoded) {
return thisStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
}
if (currentOffsetBeforeReplacement == offsetInDecoded && replacement.isNotEmpty()) {
return thisStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
if (currentOffsetBeforeReplacement == offsetInDecoded && replacement.second.isNotEmpty()) {
return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
}
currentOffsetInDecoded += deltaLength + replacement.length
encodedOffsetInCurrentLine += deltaLength + range.length
currentOffsetInDecoded += deltaLength + replacement.second.length
encodedOffsetInCurrentLine += deltaLength + replacement.first.length
}
val deltaLength = curString.length - encodedOffsetInCurrentLine
if (currentOffsetInDecoded + deltaLength > offsetInDecoded) {
return rangeStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
}
currentOffsetInDecoded += deltaLength
}

View file

@ -68,8 +68,9 @@ fun CharSequence.prefixWithTextBlockEscape(
marker: CharSequence,
indentFirst: Boolean,
prefixFirst: Boolean,
newLineAfter: Boolean
): CharSequence {
newLineAfter: Boolean,
sbFactory: (Int) -> StringBuilder = {StringBuilder(it)},
): StringBuilder {
val indentStr = if (indent >= 0) {
if (indent < COMMON_INDENT_COUNT)
COMMON_INDENTS[indent]
@ -79,7 +80,7 @@ fun CharSequence.prefixWithTextBlockEscape(
""
}
val parts = NL_MATCHER.split(this, -1)
val result = StringBuilder(length + (indentStr.length + marker.length) * parts.size + 1)
val result = sbFactory(length + (indentStr.length + marker.length) * parts.size + 1)
if (indentFirst) {
result.append('\n').append(indentStr)
}