@@ -18,6 +18,8 @@ package debug
1818import (
1919 "context"
2020 "encoding/json"
21+ "errors"
22+ "reflect"
2123 "slices"
2224 "strconv"
2325 "strings"
@@ -41,25 +43,83 @@ func GetDebugConfig(ctx context.Context, req *rpc.GetDebugConfigRequest) (*rpc.G
4143 return nil , & arduino.InvalidInstanceError {}
4244 }
4345 defer release ()
44- return getDebugProperties (req , pme )
46+ return getDebugProperties (req , pme , false )
4547}
4648
47- func getDebugProperties (req * rpc.GetDebugConfigRequest , pme * packagemanager.Explorer ) (* rpc.GetDebugConfigResponse , error ) {
48- // TODO: make a generic function to extract sketch from request
49- // and remove duplication in commands/compile.go
50- if req .GetSketchPath () == "" {
51- return nil , & arduino.MissingSketchPathError {}
49+ // IsDebugSupported checks if the given board/programmer configuration supports debugging.
50+ func IsDebugSupported (ctx context.Context , req * rpc.IsDebugSupportedRequest ) (* rpc.IsDebugSupportedResponse , error ) {
51+ pme , release := instances .GetPackageManagerExplorer (req .GetInstance ())
52+ if pme == nil {
53+ return nil , & arduino.InvalidInstanceError {}
54+ }
55+ defer release ()
56+ configRequest := & rpc.GetDebugConfigRequest {
57+ Instance : req .GetInstance (),
58+ Fqbn : req .GetFqbn (),
59+ SketchPath : "" ,
60+ Port : req .GetPort (),
61+ Interpreter : req .GetInterpreter (),
62+ ImportDir : "" ,
63+ Programmer : req .GetProgrammer (),
64+ }
65+ expectedOutput , err := getDebugProperties (configRequest , pme , true )
66+ var x * arduino.FailedDebugError
67+ if errors .As (err , & x ) {
68+ return & rpc.IsDebugSupportedResponse {DebuggingSupported : false }, nil
5269 }
53- sketchPath := paths .New (req .GetSketchPath ())
54- sk , err := sketch .New (sketchPath )
5570 if err != nil {
56- return nil , & arduino.CantOpenSketchError {Cause : err }
71+ return nil , err
72+ }
73+
74+ // Compute the minimum FQBN required to get the same debug configuration.
75+ // (i.e. the FQBN cleaned up of the options that do not affect the debugger configuration)
76+ minimumFQBN := cores .MustParseFQBN (req .GetFqbn ())
77+ for _ , config := range minimumFQBN .Configs .Keys () {
78+ checkFQBN := minimumFQBN .Clone ()
79+ checkFQBN .Configs .Remove (config )
80+ configRequest .Fqbn = checkFQBN .String ()
81+ checkOutput , err := getDebugProperties (configRequest , pme , true )
82+ if err == nil && reflect .DeepEqual (expectedOutput , checkOutput ) {
83+ minimumFQBN .Configs .Remove (config )
84+ }
85+ }
86+ return & rpc.IsDebugSupportedResponse {
87+ DebuggingSupported : true ,
88+ DebugFqbn : minimumFQBN .String (),
89+ }, nil
90+ }
91+
92+ func getDebugProperties (req * rpc.GetDebugConfigRequest , pme * packagemanager.Explorer , skipSketchChecks bool ) (* rpc.GetDebugConfigResponse , error ) {
93+ var (
94+ sketchName string
95+ sketchDefaultFQBN string
96+ sketchDefaultBuildPath * paths.Path
97+ )
98+ if ! skipSketchChecks {
99+ // TODO: make a generic function to extract sketch from request
100+ // and remove duplication in commands/compile.go
101+ if req .GetSketchPath () == "" {
102+ return nil , & arduino.MissingSketchPathError {}
103+ }
104+ sketchPath := paths .New (req .GetSketchPath ())
105+ sk , err := sketch .New (sketchPath )
106+ if err != nil {
107+ return nil , & arduino.CantOpenSketchError {Cause : err }
108+ }
109+ sketchName = sk .Name
110+ sketchDefaultFQBN = sk .GetDefaultFQBN ()
111+ sketchDefaultBuildPath = sk .DefaultBuildPath ()
112+ } else {
113+ // Use placeholder sketch data
114+ sketchName = "Sketch"
115+ sketchDefaultFQBN = ""
116+ sketchDefaultBuildPath = paths .New ("SketchBuildPath" )
57117 }
58118
59119 // XXX Remove this code duplication!!
60120 fqbnIn := req .GetFqbn ()
61- if fqbnIn == "" && sk != nil {
62- fqbnIn = sk . GetDefaultFQBN ()
121+ if fqbnIn == "" {
122+ fqbnIn = sketchDefaultFQBN
63123 }
64124 if fqbnIn == "" {
65125 return nil , & arduino.MissingFQBNError {}
@@ -109,16 +169,18 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl
109169 if importDir := req .GetImportDir (); importDir != "" {
110170 importPath = paths .New (importDir )
111171 } else {
112- importPath = sk .DefaultBuildPath ()
113- }
114- if ! importPath .Exist () {
115- return nil , & arduino.NotFoundError {Message : tr ("Compiled sketch not found in %s" , importPath )}
172+ importPath = sketchDefaultBuildPath
116173 }
117- if ! importPath .IsDir () {
118- return nil , & arduino.NotFoundError {Message : tr ("Expected compiled sketch in directory %s, but is a file instead" , importPath )}
174+ if ! skipSketchChecks {
175+ if ! importPath .Exist () {
176+ return nil , & arduino.NotFoundError {Message : tr ("Compiled sketch not found in %s" , importPath )}
177+ }
178+ if ! importPath .IsDir () {
179+ return nil , & arduino.NotFoundError {Message : tr ("Expected compiled sketch in directory %s, but is a file instead" , importPath )}
180+ }
119181 }
120182 toolProperties .SetPath ("build.path" , importPath )
121- toolProperties .Set ("build.project_name" , sk . Name + ".ino" )
183+ toolProperties .Set ("build.project_name" , sketchName + ".ino" )
122184
123185 // Set debug port property
124186 port := req .GetPort ()
0 commit comments