@@ -10,8 +10,10 @@ import (
1010 "fmt"
1111 "io/ioutil"
1212 "log"
13+ "maps"
1314 "os"
1415 "os/exec"
16+ "slices"
1517 "sort"
1618 "strconv"
1719 "strings"
@@ -47,7 +49,7 @@ func Generate(inputFile string, skipCleanup bool) ([]byte, error) {
4749 if err != nil {
4850 return nil , err
4951 }
50- b , err := asVSCodeSettings (options )
52+ b , err := asVSCodeSettingsJSON (options )
5153 if err != nil {
5254 return nil , err
5355 }
@@ -169,9 +171,17 @@ func rewritePackageJSON(newSettings, inFile string) ([]byte, error) {
169171 return bytes .TrimSpace (stdout .Bytes ()), nil
170172}
171173
172- // asVSCodeSettings converts the given options to match the VS Code settings
174+ // asVSCodeSettingsJSON converts the given options to match the VS Code settings
173175// format.
174- func asVSCodeSettings (options []* Option ) ([]byte , error ) {
176+ func asVSCodeSettingsJSON (options []* Option ) ([]byte , error ) {
177+ obj , err := asVSCodeSettings (options )
178+ if err != nil {
179+ return nil , err
180+ }
181+ return json .Marshal (obj )
182+ }
183+
184+ func asVSCodeSettings (options []* Option ) (map [string ]* Object , error ) {
175185 seen := map [string ][]* Option {}
176186 for _ , opt := range options {
177187 seen [opt .Hierarchy ] = append (seen [opt .Hierarchy ], opt )
@@ -192,7 +202,7 @@ func asVSCodeSettings(options []*Option) ([]byte, error) {
192202 AdditionalProperties : false ,
193203 Properties : goplsProperties ,
194204 }
195- return json . Marshal ( goProperties )
205+ return goProperties , nil
196206}
197207
198208func collectProperties (m map [string ][]* Option ) (goplsProperties , goProperties map [string ]* Object , err error ) {
@@ -261,18 +271,38 @@ func toObject(opt *Option) (*Object, error) {
261271 // outputs acceptable properties.
262272 // TODO: deprecation attribute
263273 }
264- // Handle any enum types.
265- if opt .Type == "enum" {
274+ if opt .Type != "enum" {
275+ obj .Type = propertyType (opt .Type )
276+ } else { // Map enum type to a sum type.
277+ // Assume value type is bool | string.
278+ seenTypes := map [string ]bool {}
266279 for _ , v := range opt .EnumValues {
267- unquotedName , err := strconv .Unquote (v .Value )
268- if err != nil {
269- return nil , err
280+ // EnumValue.Value: string in JSON syntax (quoted)
281+ var x any
282+ if err := json .Unmarshal ([]byte (v .Value ), & x ); err != nil {
283+ return nil , fmt .Errorf ("failed to unmarshal %q: %v" , v .Value , err )
284+ }
285+
286+ switch t := x .(type ) {
287+ case string :
288+ obj .Enum = append (obj .Enum , t )
289+ seenTypes ["string" ] = true
290+ case bool :
291+ obj .Enum = append (obj .Enum , t )
292+ seenTypes ["bool" ] = true
293+ default :
294+ panic (fmt .Sprintf ("type %T %+v as enum value type is not supported" , t , t ))
270295 }
271- obj .Enum = append (obj .Enum , unquotedName )
272296 obj .MarkdownEnumDescriptions = append (obj .MarkdownEnumDescriptions , v .Doc )
273297 }
274- }
275- // Handle any objects whose keys are enums.
298+ obj .Type = propertyType (slices .Sorted (maps .Keys (seenTypes ))... )
299+ }
300+ // Handle objects whose keys are listed in EnumKeys.
301+ // Gopls uses either enum or string as key types, for example,
302+ // map[string]bool: analyses
303+ // map[enum]bool: codelenses, annotations
304+ // Both cases where 'enum' is used as a key type actually use
305+ // only string type enum. For simplicity, map all to string-keyed objects.
276306 if len (opt .EnumKeys .Keys ) > 0 {
277307 if obj .Properties == nil {
278308 obj .Properties = map [string ]* Object {}
@@ -289,7 +319,6 @@ func toObject(opt *Option) (*Object, error) {
289319 }
290320 }
291321 }
292- obj .Type = propertyType (opt .Type )
293322 obj .Default = formatOptionDefault (opt )
294323
295324 return obj , nil
@@ -337,42 +366,46 @@ var associatedToExtensionProperties = map[string][]string{
337366 "buildFlags" : {"go.buildFlags" , "go.buildTags" },
338367}
339368
340- func propertyType (t string ) string {
369+ func propertyType (typs ... string ) any /* string or []string */ {
370+ if len (typs ) == 0 {
371+ panic ("unexpected: len(typs) == 0" )
372+ }
373+ if len (typs ) == 1 {
374+ return mapType (typs [0 ])
375+ }
376+
377+ var ret []string
378+ for _ , t := range typs {
379+ ret = append (ret , mapType (t ))
380+ }
381+ return ret
382+ }
383+
384+ func mapType (t string ) string {
341385 switch t {
342386 case "string" :
343387 return "string"
344388 case "bool" :
345389 return "boolean"
346- case "enum" :
347- return "string"
348390 case "time.Duration" :
349391 return "string"
350392 case "[]string" :
351393 return "array"
352394 case "map[string]string" , "map[string]bool" , "map[enum]string" , "map[enum]bool" :
353395 return "object"
354396 case "any" :
355- return "boolean" // TODO(hyangah): change to "" after https://go.dev/cl/593656 is released.
397+ return "boolean"
356398 }
357399 log .Fatalf ("unknown type %q" , t )
358400 return ""
359401}
360402
361- func check (err error ) {
362- if err == nil {
363- return
364- }
365-
366- log .Output (1 , err .Error ())
367- os .Exit (1 )
368- }
369-
370403// Object represents a VS Code settings object.
371404type Object struct {
372- Type string `json:"type,omitempty"`
405+ Type any `json:"type,omitempty"` // string | []string
373406 MarkdownDescription string `json:"markdownDescription,omitempty"`
374407 AdditionalProperties bool `json:"additionalProperties,omitempty"`
375- Enum []string `json:"enum,omitempty"`
408+ Enum []any `json:"enum,omitempty"`
376409 MarkdownEnumDescriptions []string `json:"markdownEnumDescriptions,omitempty"`
377410 Default interface {} `json:"default,omitempty"`
378411 Scope string `json:"scope,omitempty"`
@@ -395,6 +428,7 @@ type API struct {
395428 Options map [string ][]* Option
396429 Lenses []* Lens
397430 Analyzers []* Analyzer
431+ Hints []* Hint
398432}
399433
400434type Option struct {
0 commit comments