in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStringParserBase.kt [317:488]
override fun parseVimScriptString(string: String): String {
val result = StringBuilder()
var state = VimStringState.INIT
var specialKeyBuilder: StringBuilder? = null
var digitsLeft = 0
var number = 0
val vimStringWithForceEnd = string + 0.toChar()
var i = 0
while (i < vimStringWithForceEnd.length) {
val c = vimStringWithForceEnd[i]
when (state) {
VimStringState.INIT -> if (c == '\\') {
state = VimStringState.ESCAPE
} else if (c.code == 0) {
i = vimStringWithForceEnd.length
} else {
result.append(c)
}
VimStringState.ESCAPE -> {
val octalToDigital = octalDigitToNumber(c)
if (octalToDigital != null) {
number = octalToDigital
digitsLeft = 2
state = VimStringState.OCTAL_NUMBER
} else if (Character.toLowerCase(c) == 'x') {
digitsLeft = 2
state = VimStringState.HEX_NUMBER
} else if (c == 'u') {
digitsLeft = 4
state = VimStringState.HEX_NUMBER
} else if (c == 'U') {
digitsLeft = 8
state = VimStringState.HEX_NUMBER
} else if (c == 'b') {
result.append(8.toChar())
state = VimStringState.INIT
} else if (c == 'e') {
result.append(27.toChar())
state = VimStringState.INIT
} else if (c == 'f') {
result.append(12.toChar())
state = VimStringState.INIT
} else if (c == 'n') {
result.append('\n')
state = VimStringState.INIT
} else if (c == 'r') {
result.append('\r')
state = VimStringState.INIT
} else if (c == 't') {
result.append('\t')
state = VimStringState.INIT
} else if (c == '\\') {
result.append('\\')
state = VimStringState.INIT
} else if (c == '"') {
result.append('"')
state = VimStringState.INIT
} else if (c == '<') {
state = VimStringState.SPECIAL
specialKeyBuilder = StringBuilder()
} else if (c.code == 0) {
i = vimStringWithForceEnd.length // force end of the string
} else {
result.append(c)
state = VimStringState.INIT
}
}
VimStringState.OCTAL_NUMBER -> {
val value = octalDigitToNumber(c)
if (value != null) {
digitsLeft -= 1
number = number * 8 + value
if (digitsLeft == 0 || i == vimStringWithForceEnd.length - 1) {
if (number != 0) {
result.append(number.toChar())
} else {
i = vimStringWithForceEnd.length
}
number = 0
state = VimStringState.INIT
}
} else {
if (number != 0) {
result.append(number.toChar())
} else {
i = vimStringWithForceEnd.length
}
number = 0
digitsLeft = 0
state = VimStringState.INIT
i -= 1
}
}
VimStringState.HEX_NUMBER -> {
val `val` = hexDigitToNumber(c)
if (`val` == null) {
// if there was at least one number after '\', append number, otherwise - append letter after '\'
if (vimStringWithForceEnd[i - 2] == '\\') {
result.append(vimStringWithForceEnd[i - 1])
} else {
if (number != 0) {
result.append(number.toChar())
} else {
i = vimStringWithForceEnd.length
}
}
number = 0
digitsLeft = 0
state = VimStringState.INIT
i -= 1
} else {
number = number * 16 + `val`
digitsLeft -= 1
if (digitsLeft == 0 || i == vimStringWithForceEnd.length - 1) {
if (number != 0) {
result.append(number.toChar())
} else {
i = vimStringWithForceEnd.length
}
number = 0
state = VimStringState.INIT
}
}
}
VimStringState.SPECIAL -> {
if (c.code == 0) {
result.append(specialKeyBuilder)
}
if (c == '>') {
val specialKey = parseSpecialKey(specialKeyBuilder.toString(), 0)
if (specialKey != null) {
var keyCode = specialKey.keyCode
var useKeyCode = true
if (specialKey.keyCode == 0) {
keyCode = specialKey.keyChar.code
} else if (specialKey.modifiers and InputEvent.CTRL_DOWN_MASK == InputEvent.CTRL_DOWN_MASK) {
if (isControlCharacterKeyCode(specialKey.keyCode)) {
keyCode = if (specialKey.keyCode == 'J'.code) {
// 'J' is a special case, keycode 10 is \n char
0
} else {
specialKey.keyCode - 'A'.code + 1
}
} else {
useKeyCode = false
result.append("\\<${specialKeyBuilder}>")
}
}
if (useKeyCode) {
result.append(keyCode.toChar())
}
} else {
result.append("<").append(specialKeyBuilder).append(">")
}
specialKeyBuilder = StringBuilder()
state = VimStringState.INIT
} else if (c.code == 0) {
result.append("<").append(specialKeyBuilder)
state = VimStringState.INIT
} else {
specialKeyBuilder!!.append(c)
}
}
}
i += 1
}
return result.toString()
}