github.com/elves/Elvish@v0.12.0/parse/quote.go (about) 1 package parse 2 3 import ( 4 "bytes" 5 "unicode" 6 ) 7 8 // Quote returns a representation of s in elvish syntax. Bareword is tried 9 // first, then single quoted string and finally double quoted string. 10 func Quote(s string) string { 11 s, _ = QuoteAs(s, Bareword) 12 return s 13 } 14 15 // QuoteAs returns a representation of s in elvish syntax, using the syntax 16 // specified by q, which must be one of Bareword, SingleQuoted, or 17 // DoubleQuoted. It returns the quoted string and the actual quoting. 18 func QuoteAs(s string, q PrimaryType) (string, PrimaryType) { 19 if q == DoubleQuoted { 20 // Everything can be quoted using double quotes, return directly. 21 return quoteDouble(s), DoubleQuoted 22 } 23 if s == "" { 24 return "''", SingleQuoted 25 } 26 27 // Keep track of whether it is a valid bareword. 28 bare := s[0] != '~' 29 for _, r := range s { 30 if !unicode.IsPrint(r) { 31 // Contains unprintable character; force double quote. 32 return quoteDouble(s), DoubleQuoted 33 } 34 if !allowedInBareword(r, strictExpr) { 35 bare = false 36 } 37 } 38 39 if q == Bareword && bare { 40 return s, Bareword 41 } 42 return quoteSingle(s), SingleQuoted 43 } 44 45 func quoteSingle(s string) string { 46 var buf bytes.Buffer 47 buf.WriteByte('\'') 48 for _, r := range s { 49 buf.WriteRune(r) 50 if r == '\'' { 51 buf.WriteByte('\'') 52 } 53 } 54 buf.WriteByte('\'') 55 return buf.String() 56 } 57 58 func rtohex(r rune, w int) []byte { 59 bytes := make([]byte, w) 60 for i := w - 1; i >= 0; i-- { 61 d := byte(r % 16) 62 r /= 16 63 if d <= 9 { 64 bytes[i] = '0' + d 65 } else { 66 bytes[i] = 'a' + d - 10 67 } 68 } 69 return bytes 70 } 71 72 func quoteDouble(s string) string { 73 var buf bytes.Buffer 74 buf.WriteByte('"') 75 for _, r := range s { 76 if e, ok := doubleUnescape[r]; ok { 77 // Takes care of " and \ as well. 78 buf.WriteByte('\\') 79 buf.WriteRune(e) 80 } else if !unicode.IsPrint(r) { 81 buf.WriteByte('\\') 82 if r <= 0xff { 83 buf.WriteByte('x') 84 buf.Write(rtohex(r, 2)) 85 } else if r <= 0xffff { 86 buf.WriteByte('u') 87 buf.Write(rtohex(r, 4)) 88 } else { 89 buf.WriteByte('U') 90 buf.Write(rtohex(r, 8)) 91 } 92 } else { 93 buf.WriteRune(r) 94 } 95 } 96 buf.WriteByte('"') 97 return buf.String() 98 }