output.go (1634B)
1 package internal 2 3 import ( 4 "bytes" 5 "errors" 6 "go/format" 7 "go/scanner" 8 "io" 9 "strings" 10 "unicode" 11 ) 12 13 // Identifier turns a C style type or field name into an exportable Go equivalent. 14 func Identifier(str string) string { 15 prev := rune(-1) 16 return strings.Map(func(r rune) rune { 17 // See https://golang.org/ref/spec#Identifiers 18 switch { 19 case unicode.IsLetter(r): 20 if prev == -1 { 21 r = unicode.ToUpper(r) 22 } 23 24 case r == '_': 25 switch { 26 // The previous rune was deleted, or we are at the 27 // beginning of the string. 28 case prev == -1: 29 fallthrough 30 31 // The previous rune is a lower case letter or a digit. 32 case unicode.IsDigit(prev) || (unicode.IsLetter(prev) && unicode.IsLower(prev)): 33 // delete the current rune, and force the 34 // next character to be uppercased. 35 r = -1 36 } 37 38 case unicode.IsDigit(r): 39 40 default: 41 // Delete the current rune. prev is unchanged. 42 return -1 43 } 44 45 prev = r 46 return r 47 }, str) 48 } 49 50 // WriteFormatted outputs a formatted src into out. 51 // 52 // If formatting fails it returns an informative error message. 53 func WriteFormatted(src []byte, out io.Writer) error { 54 formatted, err := format.Source(src) 55 if err == nil { 56 _, err = out.Write(formatted) 57 return err 58 } 59 60 var el scanner.ErrorList 61 if !errors.As(err, &el) { 62 return err 63 } 64 65 var nel scanner.ErrorList 66 for _, err := range el { 67 if !err.Pos.IsValid() { 68 nel = append(nel, err) 69 continue 70 } 71 72 buf := src[err.Pos.Offset:] 73 nl := bytes.IndexRune(buf, '\n') 74 if nl == -1 { 75 nel = append(nel, err) 76 continue 77 } 78 79 err.Msg += ": " + string(buf[:nl]) 80 nel = append(nel, err) 81 } 82 83 return nel 84 }