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 // write appends the string `s` to the buffer
[inline] [inline]
pub fn (mut b Builder) write_string(s string) { pub fn (mut b Builder) write_string(s string) {
if s == '' { if s.len == 0 {
return return
} }
unsafe { b.push_many(s.str, s.len) } unsafe { b.push_many(s.str, s.len) }

View File

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