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 package com.falsepattern.zigbrains.zig.intentions
import com.falsepattern.zigbrains.zig.psi.ZigStringLiteral 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.falsepattern.zigbrains.zig.util.escape
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@ -29,8 +27,12 @@ class MakeStringQuoted: PsiElementBaseIntentionAction() {
if (!str.isMultiline) if (!str.isMultiline)
return return
val escaper = str.createLiteralTextEscaper() val escaper = str.createLiteralTextEscaper()
val (contentStart, contentEnd) = escaper.relevantTextRange val contentRange = escaper.relevantTextRange
val (fullStart, fullEnd) = str.textRange 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 var caretOffset = editor.caretModel.offset
val prefix = TextRange(contentStart, max(contentStart, caretOffset - fullStart)) val prefix = TextRange(contentStart, max(contentStart, caretOffset - fullStart))
val suffix = TextRange(min(contentEnd, caretOffset - fullStart), contentEnd) 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 com.intellij.util.MathUtil
import kotlin.math.max import kotlin.math.max
fun getTextRangeBounds(contentRanges: List<TextRange>): TextRange = fun getTextRangeBounds(contentRanges: List<TextRange>): TextRange =
if (contentRanges.isEmpty()) if (contentRanges.isEmpty())
TextRange.EMPTY_RANGE TextRange.EMPTY_RANGE
else else
TextRange.create(contentRanges.first().startOffset, contentRanges.last().endOffset) 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 result = ArrayList<TextRange>()
val textLength = this.length var stringStart = 0
val markLength = startMark.length var inBody = false
var offset = 0 val textLength = length
val firstChar = startMark[0]
while (offset < textLength) { val extraChars = startMark.substring(1)
val markIndex = this.indexOf(startMark, offset) var i = 0
if (markIndex < 0) loop@ while (i < textLength) {
break val cI = this[i]
val stringStart = markIndex + markLength if (!inBody) {
if (cI == firstChar &&
var found: Int? = null i + extraChars.length < textLength
findEnd@ for (end in stringStart until textLength) { ) {
val cI = this[end] for (j in extraChars.indices) {
when (cI) { if (this[i + j + 1] != startMark[j]) {
'\r' -> { i++
if (end + 1 < textLength && this[end + 1] == '\n') { continue@loop
found = end + 2
break@findEnd
} }
found = end + 1
break@findEnd
}
'\n' -> {
found = end + 1
break@findEnd
} }
i += extraChars.length
inBody = true
stringStart = i + 1
} }
} 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))
)
)
} }
if (found == null) i++
break
result.add(TextRange(stringStart, kotlin.math.min(textLength - 1, found)))
offset = found
} }
return result return result
} }
@ -73,7 +83,9 @@ fun splitString(
val token = psiAtOffset.node val token = psiAtOffset.node
val text = document.charsSequence val text = document.charsSequence
val (rangeStart, rangeEnd) = token.textRange val range = token.textRange
val rangeStart = range.startOffset
val rangeEnd = range.endOffset
val lexer = ZigLexerStringAdapter() val lexer = ZigLexerStringAdapter()
lexer.start(text, rangeStart, rangeEnd) lexer.start(text, rangeStart, rangeEnd)
caretOffset = lexer.skipStringLiteralEscapes(caretOffset) caretOffset = lexer.skipStringLiteralEscapes(caretOffset)
@ -141,12 +153,3 @@ private fun Lexer.skipStringLiteralEscapes(caretOffset: Int): Int {
} }
return caretOffset 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.openapi.util.TextRange
import com.intellij.psi.LiteralTextEscaper import com.intellij.psi.LiteralTextEscaper
import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.impl.source.tree.LeafElement
import java.lang.StringBuilder
abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(node), ZigStringLiteral { abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(node), ZigStringLiteral {
override fun isValidHost() = true override fun isValidHost() = true
@ -20,7 +19,7 @@ abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(no
get() = if (!isMultiline) { get() = if (!isMultiline) {
listOf(TextRange(1, textLength - 1)) listOf(TextRange(1, textLength - 1))
} else { } else {
text.getMultiLineContent("\\\\") text.getMultilineContent("\\\\")
} }
override fun updateText(text: String): ZigStringLiteral { override fun updateText(text: String): ZigStringLiteral {
@ -60,33 +59,30 @@ abstract class ZigStringLiteralMixinImpl(node: ASTNode): ASTWrapperPsiElement(no
var currentOffsetInDecoded = 0 var currentOffsetInDecoded = 0
var last: TextRange? = null var last: TextRange? = null
val isMultiline = myHost.isMultiline for (i in contentRanges.indices) {
for (range in contentRanges) { val range = rangeInsideHost.intersection(contentRanges[i]) ?: continue
last = range last = range
val (rangeStart, _) = range val curString = range.substring(text)
val curString = range.subSequence(text) val replacementsForThisLine = curString.decodeReplacements(myHost.isMultiline)
val replacementsForThisLine = curString.decodeReplacements(isMultiline)
var encodedOffsetInCurrentLine = 0 var encodedOffsetInCurrentLine = 0
for ((thisRange, replacement) in replacementsForThisLine) { for (replacement in replacementsForThisLine) {
val (thisStart, _) = thisRange val deltaLength = replacement.first.startOffset - encodedOffsetInCurrentLine
val deltaLength = thisStart - encodedOffsetInCurrentLine
val currentOffsetBeforeReplacement = currentOffsetInDecoded + deltaLength val currentOffsetBeforeReplacement = currentOffsetInDecoded + deltaLength
if (currentOffsetBeforeReplacement > offsetInDecoded) { if (currentOffsetBeforeReplacement > offsetInDecoded) {
return thisStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded) return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
} }
if (currentOffsetBeforeReplacement == offsetInDecoded && replacement.isNotEmpty()) { if (currentOffsetBeforeReplacement == offsetInDecoded && replacement.second.isNotEmpty()) {
return thisStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded) return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
} }
currentOffsetInDecoded += deltaLength + replacement.length currentOffsetInDecoded += deltaLength + replacement.second.length
encodedOffsetInCurrentLine += deltaLength + range.length encodedOffsetInCurrentLine += deltaLength + replacement.first.length
} }
val deltaLength = curString.length - encodedOffsetInCurrentLine val deltaLength = curString.length - encodedOffsetInCurrentLine
if (currentOffsetInDecoded + deltaLength > offsetInDecoded) { if (currentOffsetInDecoded + deltaLength > offsetInDecoded) {
return rangeStart + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded) return range.startOffset + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded)
} }
currentOffsetInDecoded += deltaLength currentOffsetInDecoded += deltaLength
} }

View file

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