v.util: make util.smart_quote use its output string builder directly

pull/10533/head
Delyan Angelov 2021-06-20 20:55:12 +03:00
parent 81fe702b77
commit 45c6b6493b
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
2 changed files with 73 additions and 47 deletions

View File

@ -45,7 +45,7 @@ pub fn (b &Builder) byte_at(n int) byte {
// write appends the string `s` to the buffer
[inline]
pub fn (mut b Builder) write_string(s string) {
if s == '' {
if s.len == 0 {
return
}
unsafe { b.push_many(s.str, s.len) }

View File

@ -2,93 +2,119 @@ module util
import strings
const (
invalid_escapes = ['(', '{', '$', '`', '.']
)
const invalid_escapes = r'({$`.'.bytes()
[direct_array_access]
const backslash = 92
const backslash_r = 13
const backslash_n = 10
const double_quote = 34
const double_escape = '\\\\'
//[direct_array_access]
pub fn smart_quote(str string, raw bool) string {
len := str.len
if len == 0 {
return str
return ''
}
mut result := strings.new_builder(len)
mut pos := -1
mut last := ''
// TODO: This should be a single char?
mut next := ''
mut last := byte(0)
mut current := byte(0)
mut next := byte(0)
mut skip_next := false
for {
pos = pos + 1
pos++
if skip_next {
skip_next = false
pos = pos + 1
pos++
}
if pos >= len {
break
}
if pos + 1 < len {
next = str[pos + 1].ascii_str()
}
mut current := str
mut toadd := str
if len > 1 {
current = str[pos].ascii_str()
toadd = current
next = str[pos + 1]
}
current = str[pos]
// double quote
if current == '"' {
toadd = '\\"'
current = ''
if current == util.double_quote {
current = 0
last = current
result.write_b(util.backslash)
result.write_b(util.double_quote)
continue
}
if current == '\\' {
if current == util.backslash {
if raw {
toadd = '\\\\'
last = current
result.write_string(util.double_escape)
continue
} else {
// escaped backslash - keep as is
if next == '\\' {
toadd = '\\\\'
if next == util.backslash {
skip_next = true
} else if next != '' {
last = current
result.write_string(util.double_escape)
continue
} else if next != 0 {
if raw {
toadd = '\\\\' + next
skip_next = true
}
// keep all valid escape sequences
else if next !in util.invalid_escapes {
toadd = '\\' + next
last = current
result.write_string(util.double_escape)
continue
} else if next in util.invalid_escapes {
skip_next = true
last = current
result.write_b(next)
continue
} else {
toadd = next
// keep all valid escape sequences
skip_next = true
last = current
result.write_b(current)
result.write_b(next)
continue
}
}
}
}
// keep newlines in string
if current == '\n' {
toadd = '\\n'
current = ''
} else if current == '\r' && next == '\n' {
toadd = '\r\n'
current = ''
if current == util.backslash_n {
current = 0
last = current
result.write_b(util.backslash)
result.write_b(`n`)
continue
} else if current == util.backslash_r && next == util.backslash_n {
result.write_b(current)
result.write_b(next)
current = 0
skip_next = true
last = current
continue
}
// Dolar sign
if !raw && current == '$' {
if last == '\\' {
toadd = r'\$'
if !raw && current == `$` {
if last == util.backslash {
result.write_b(last)
result.write_b(current)
last = current
continue
}
}
// Windows style new line \r\n
if !raw && current == '\r' {
if next == '\n' {
skip_next = true
toadd = '\\n'
}
if !raw && current == util.backslash_r && next == util.backslash_n {
skip_next = true
result.write_b(util.backslash)
result.write_b(`n`)
last = current
continue
}
result.write_string(toadd)
last = current
result.write_b(current)
}
return result.str()
}