diff --git a/commands/debug/debug_info.go b/commands/debug/debug_info.go index a8731ab1d6a..d85a766270b 100644 --- a/commands/debug/debug_info.go +++ b/commands/debug/debug_info.go @@ -19,6 +19,7 @@ import ( "context" "encoding/json" "regexp" + "strconv" "strings" "github.com/arduino/arduino-cli/arduino" @@ -209,28 +210,56 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl // my.indexed.array.2=third // // into the corresponding JSON arrays. +// If a value should be converted into a JSON type different from string, the value +// may be prefiex with "[boolean]", "[number]", or "[object]": +// +// my.stringValue=a string +// my.booleanValue=[boolean]true +// my.numericValue=[number]20 func convertToJsonMap(in *properties.Map) string { - // XXX: Maybe this method could be a good candidate for propertis.Map? - // Find the values that should be kept as is, and the indexed arrays // that should be later converted into arrays. arraysKeys := map[string]bool{} - stringKeys := []string{} + scalarKeys := []string{} trailingNumberMatcher := regexp.MustCompile(`^(.*)\.[0-9]+$`) for _, k := range in.Keys() { match := trailingNumberMatcher.FindAllStringSubmatch(k, -1) if len(match) > 0 && len(match[0]) > 1 { arraysKeys[match[0][1]] = true } else { - stringKeys = append(stringKeys, k) + scalarKeys = append(scalarKeys, k) } } // Compose a map that can be later marshaled into JSON keeping // the arrays where they are expected to be. res := map[string]any{} - for _, k := range stringKeys { - res[k] = in.Get(k) + for _, k := range scalarKeys { + v := in.Get(k) + switch { + case strings.HasPrefix(v, "[boolean]"): + v = strings.TrimSpace(strings.TrimPrefix(v, "[boolean]")) + if strings.EqualFold(v, "true") { + res[k] = true + } else if strings.EqualFold(v, "false") { + res[k] = false + } + case strings.HasPrefix(v, "[number]"): + v = strings.TrimPrefix(v, "[number]") + if i, err := strconv.Atoi(v); err == nil { + res[k] = i + } else if f, err := strconv.ParseFloat(v, 64); err == nil { + res[k] = f + } + case strings.HasPrefix(v, "[object]"): + v = strings.TrimPrefix(v, "[object]") + var o interface{} + if err := json.Unmarshal([]byte(v), &o); err == nil { + res[k] = o + } + default: + res[k] = v + } } for k := range arraysKeys { res[k] = in.ExtractSubIndexLists(k) diff --git a/docs/platform-specification.md b/docs/platform-specification.md index c34047bf8d9..ec2f4a3dc3e 100644 --- a/docs/platform-specification.md +++ b/docs/platform-specification.md @@ -1403,6 +1403,30 @@ will result in the following JSON to be merged in the Arduino IDE generated `lau } ``` +All the values are converted by default to a string in the resulting JSON. If another type is needed the value can be +prefixed with the tags `[boolean]`, `[number]`, or `[object]` to force a specific type in the JSON, for example: + +``` +debug.cortex-debug.custom.aBoolean=[boolean]true +debug.cortex-debug.custom.aNumber=[number]10 +debug.cortex-debug.custom.anotherNumber=[number]10.20 +debug.cortex-debug.custom.anObject=[object]{"key":"value", "boolean":true} +``` + +will result in the following JSON: + +```json +{ + "aBoolean": true, + "aNumber": 10, + "anotherNumber": 10.2, + "anObject": { + "boolean": true, + "key": "value" + } +} +``` + ### Optimization level for debugging The compiler optimization level that is appropriate for normal usage will often not provide a good experience while diff --git a/internal/integrationtest/debug/debug_test.go b/internal/integrationtest/debug/debug_test.go index 0d3a0cc9dbf..4931fa1e9b5 100644 --- a/internal/integrationtest/debug/debug_test.go +++ b/internal/integrationtest/debug/debug_test.go @@ -133,6 +133,15 @@ func testAllDebugInformation(t *testing.T, env *integrationtest.Environment, cli }, "svd_file": "svd-file", "cortex-debug_custom_configuration": { + "aBoolean": true, + "aStringBoolean": "true", + "aStringNumber": "10", + "aNumber": 10, + "anotherNumber": 10.2, + "anObject": { + "boolean": true, + "key": "value" + }, "anotherStringParamer": "hellooo", "overrideRestartCommands": [ "monitor reset halt", @@ -176,6 +185,15 @@ func testAllDebugInformation(t *testing.T, env *integrationtest.Environment, cli }, "svd_file": "svd-file", "cortex-debug_custom_configuration": { + "aBoolean": true, + "aStringBoolean": "true", + "aStringNumber": "10", + "aNumber": 10, + "anotherNumber": 10.2, + "anObject": { + "boolean": true, + "key": "value" + }, "anotherStringParamer": "hellooo", "overrideRestartCommands": [ "monitor reset halt", diff --git a/internal/integrationtest/debug/testdata/hardware/my/samd/boards.txt b/internal/integrationtest/debug/testdata/hardware/my/samd/boards.txt index 987aa196fdd..faf869329be 100644 --- a/internal/integrationtest/debug/testdata/hardware/my/samd/boards.txt +++ b/internal/integrationtest/debug/testdata/hardware/my/samd/boards.txt @@ -44,6 +44,12 @@ my.debug.cortex-debug.custom.overrideRestartCommands.1=monitor gdb_sync my.debug.cortex-debug.custom.overrideRestartCommands.2=thb setup my.debug.cortex-debug.custom.overrideRestartCommands.3=c my.debug.cortex-debug.custom.anotherStringParamer=hellooo +my.debug.cortex-debug.custom.aBoolean=[boolean]true +my.debug.cortex-debug.custom.aStringBoolean=true +my.debug.cortex-debug.custom.aNumber=[number]10 +my.debug.cortex-debug.custom.anotherNumber=[number]10.20 +my.debug.cortex-debug.custom.aStringNumber=10 +my.debug.cortex-debug.custom.anObject=[object]{"key":"value", "boolean":true} my.debug.svd_file=svd-file my2.name=My Cool Board