string stuff cleanup and bugfixes
This commit is contained in:
parent
cd474221a6
commit
431e09830f
4 changed files with 67 additions and 65 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
if (found == null)
|
} else if (cI == '\r') {
|
||||||
break
|
if (i + 1 < length && this[i + 1] == '\n') {
|
||||||
|
i++
|
||||||
result.add(TextRange(stringStart, kotlin.math.min(textLength - 1, found)))
|
}
|
||||||
offset = found
|
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
|
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
|
|
||||||
}
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue