2
2
import { VariableContribution , VariableRegistry , Variable } from '@theia/variable-resolver/lib/browser' ;
3
3
import { injectable , inject } from 'inversify' ;
4
4
import URI from '@theia/core/lib/common/uri' ;
5
+ import { MessageService } from '@theia/core/lib/common/message-service' ;
6
+ import { ApplicationShell , Navigatable } from '@theia/core/lib/browser' ;
7
+ import { FileStat , FileSystem } from '@theia/filesystem/lib/common' ;
8
+ import { WorkspaceVariableContribution } from '@theia/workspace/lib/browser/workspace-variable-contribution' ;
5
9
import { BoardsServiceClientImpl } from 'arduino-ide-extension/lib/browser/boards/boards-service-client-impl' ;
6
10
import { BoardsService , ToolLocations } from 'arduino-ide-extension/lib/common/protocol/boards-service' ;
7
- import { WorkspaceVariableContribution } from '@theia/workspace/lib/browser/workspace-variable-contribution' ;
8
11
9
12
@injectable ( )
10
13
export class ArduinoVariableResolver implements VariableContribution {
@@ -18,64 +21,134 @@ export class ArduinoVariableResolver implements VariableContribution {
18
21
@inject ( WorkspaceVariableContribution )
19
22
protected readonly workspaceVars : WorkspaceVariableContribution ;
20
23
24
+ @inject ( ApplicationShell )
25
+ protected readonly applicationShell : ApplicationShell ;
26
+
27
+ @inject ( FileSystem )
28
+ protected readonly fileSystem : FileSystem ;
29
+
30
+ @inject ( MessageService )
31
+ protected readonly messageService : MessageService
32
+
21
33
registerVariables ( variables : VariableRegistry ) : void {
22
34
variables . registerVariable ( < Variable > {
23
- name : ` boardTools` ,
24
- description : " Provides paths and access to board specific tooling" ,
35
+ name : ' boardTools' ,
36
+ description : ' Provides paths and access to board specific tooling' ,
25
37
resolve : this . resolveBoardTools . bind ( this ) ,
26
38
} ) ;
27
39
variables . registerVariable ( < Variable > {
28
- name : " board" ,
29
- description : " Provides details about the currently selected board" ,
40
+ name : ' board' ,
41
+ description : ' Provides details about the currently selected board' ,
30
42
resolve : this . resolveBoard . bind ( this ) ,
31
43
} ) ;
32
-
33
44
variables . registerVariable ( {
34
- name : " sketchBinary" ,
35
- description : " Path to the sketch's binary file" ,
45
+ name : ' sketchBinary' ,
46
+ description : ' Path to the sketch\ 's binary file' ,
36
47
resolve : this . resolveSketchBinary . bind ( this )
37
48
} ) ;
38
49
}
39
50
40
- // TODO: this function is a total hack. Instead of botching around with URI's it should ask something on the backend
41
- // that properly udnerstands the filesystem.
42
- protected async resolveSketchBinary ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < Object > {
43
- let sketchPath = argument || this . workspaceVars . getResourceUri ( ) ! . path . toString ( ) ;
44
- return sketchPath . substring ( 0 , sketchPath . length - 3 ) + "arduino.samd.arduino_zero_edbg.elf" ;
51
+ protected resolveSketchBinary ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < Object | undefined > {
52
+ if ( argument ) {
53
+ return this . resolveBinaryWithHint ( argument ) ;
54
+ }
55
+ const resourceUri = this . workspaceVars . getResourceUri ( ) ;
56
+ if ( resourceUri ) {
57
+ return this . resolveBinaryWithHint ( resourceUri . toString ( ) ) ;
58
+ }
59
+ for ( const tabBar of this . applicationShell . mainAreaTabBars ) {
60
+ if ( tabBar . currentTitle && Navigatable . is ( tabBar . currentTitle . owner ) ) {
61
+ const uri = tabBar . currentTitle . owner . getResourceUri ( ) ;
62
+ if ( uri ) {
63
+ return this . resolveBinaryWithHint ( uri . toString ( ) ) ;
64
+ }
65
+ }
66
+ }
67
+ this . messageService . error ( 'No sketch available. Please open a sketch to start debugging.' ) ;
68
+ return Promise . resolve ( undefined ) ;
69
+ }
70
+
71
+ private async resolveBinaryWithHint ( hint : string ) : Promise < string | undefined > {
72
+ const fileStat = await this . fileSystem . getFileStat ( hint ) ;
73
+ if ( ! fileStat ) {
74
+ this . messageService . error ( 'Cannot find sketch binary: ' + hint ) ;
75
+ return undefined ;
76
+ }
77
+ if ( ! fileStat . isDirectory && fileStat . uri . endsWith ( '.elf' ) ) {
78
+ return fileStat . uri ;
79
+ }
80
+
81
+ let parent : FileStat | undefined ;
82
+ let prefix : string | undefined ;
83
+ let suffix : string ;
84
+ if ( fileStat . isDirectory ) {
85
+ parent = fileStat ;
86
+ } else {
87
+ const uri = new URI ( fileStat . uri ) ;
88
+ parent = await this . fileSystem . getFileStat ( uri . parent . toString ( ) ) ;
89
+ prefix = uri . path . name ;
90
+ }
91
+ const { boardsConfig } = this . boardsServiceClient ;
92
+ if ( boardsConfig && boardsConfig . selectedBoard && boardsConfig . selectedBoard . fqbn ) {
93
+ suffix = boardsConfig . selectedBoard . fqbn . replace ( / : / g, '.' ) + '.elf' ;
94
+ } else {
95
+ suffix = '.elf' ;
96
+ }
97
+ if ( parent && parent . children ) {
98
+ let bin : FileStat | undefined ;
99
+ if ( prefix ) {
100
+ bin = parent . children . find ( c => c . uri . startsWith ( prefix ! ) && c . uri . endsWith ( suffix ) ) ;
101
+ }
102
+ if ( ! bin ) {
103
+ bin = parent . children . find ( c => c . uri . endsWith ( suffix ) ) ;
104
+ }
105
+ if ( ! bin && suffix . length > 4 ) {
106
+ bin = parent . children . find ( c => c . uri . endsWith ( '.elf' ) ) ;
107
+ }
108
+ if ( bin ) {
109
+ return bin . uri ;
110
+ }
111
+ }
112
+ this . messageService . error ( 'Cannot find sketch binary: ' + hint ) ;
113
+ return undefined ;
45
114
}
46
115
47
- protected async resolveBoard ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < Object > {
116
+ protected async resolveBoard ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < string | undefined > {
48
117
const { boardsConfig } = this . boardsServiceClient ;
49
118
if ( ! boardsConfig || ! boardsConfig . selectedBoard ) {
50
- throw new Error ( 'No boards selected. Please select a board.' ) ;
119
+ this . messageService . error ( 'No boards selected. Please select a board.' ) ;
120
+ return undefined ;
51
121
}
52
122
53
- if ( ! argument || argument === " fqbn" ) {
123
+ if ( ! argument || argument === ' fqbn' ) {
54
124
return boardsConfig . selectedBoard . fqbn ! ;
55
125
}
56
- if ( argument === " name" ) {
126
+ if ( argument === ' name' ) {
57
127
return boardsConfig . selectedBoard . name ;
58
128
}
59
129
60
- const details = await this . boardsService . detail ( { id : boardsConfig . selectedBoard . fqbn ! } ) ;
130
+ const details = await this . boardsService . detail ( { id : boardsConfig . selectedBoard . fqbn ! } ) ;
61
131
if ( ! details . item ) {
62
- throw new Error ( "Cannot get board details" ) ;
132
+ this . messageService . error ( 'Details of the selected boards are not available.' ) ;
133
+ return undefined ;
63
134
}
64
- if ( argument === " openocd-debug-file" ) {
135
+ if ( argument === ' openocd-debug-file' ) {
65
136
return details . item . locations ! . debugScript ;
66
137
}
67
138
68
139
return boardsConfig . selectedBoard . fqbn ! ;
69
140
}
70
141
71
- protected async resolveBoardTools ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < Object > {
142
+ protected async resolveBoardTools ( context ?: URI , argument ?: string , configurationSection ?: string ) : Promise < string | undefined > {
72
143
const { boardsConfig } = this . boardsServiceClient ;
73
144
if ( ! boardsConfig || ! boardsConfig . selectedBoard ) {
74
- throw new Error ( 'No boards selected. Please select a board.' ) ;
145
+ this . messageService . error ( 'No boards selected. Please select a board.' ) ;
146
+ return undefined ;
75
147
}
76
- const details = await this . boardsService . detail ( { id : boardsConfig . selectedBoard . fqbn ! } ) ;
148
+ const details = await this . boardsService . detail ( { id : boardsConfig . selectedBoard . fqbn ! } ) ;
77
149
if ( ! details . item ) {
78
- throw new Error ( "Cannot get board details" )
150
+ this . messageService . error ( 'Details of the selected boards are not available.' ) ;
151
+ return undefined ;
79
152
}
80
153
81
154
let toolLocations : { [ name : string ] : ToolLocations } = { } ;
@@ -84,17 +157,37 @@ export class ArduinoVariableResolver implements VariableContribution {
84
157
} )
85
158
86
159
switch ( argument ) {
87
- case "openocd" :
88
- return toolLocations [ "openocd" ] . main ;
89
- case "openocd-scripts" :
90
- return toolLocations [ "openocd" ] . scripts ;
91
- case "objdump" :
92
- return toolLocations [ "arm-none-eabi-gcc" ] . objdump ;
93
- case "gdb" :
94
- return toolLocations [ "arm-none-eabi-gcc" ] . gdb ;
160
+ case 'openocd' : {
161
+ const openocd = toolLocations [ 'openocd' ] ;
162
+ if ( openocd ) {
163
+ return openocd . main ;
164
+ }
165
+ this . messageService . error ( 'Unable to find debugging tool: openocd' ) ;
166
+ return undefined ;
167
+ }
168
+ case 'openocd-scripts' : {
169
+ const openocd = toolLocations [ 'openocd' ] ;
170
+ return openocd ? openocd . scripts : undefined ;
171
+ }
172
+ case 'objdump' : {
173
+ const gcc = Object . keys ( toolLocations ) . find ( key => key . endsWith ( 'gcc' ) ) ;
174
+ if ( gcc ) {
175
+ return toolLocations [ gcc ] . objdump ;
176
+ }
177
+ this . messageService . error ( 'Unable to find debugging tool: objdump' ) ;
178
+ return undefined ;
179
+ }
180
+ case 'gdb' : {
181
+ const gcc = Object . keys ( toolLocations ) . find ( key => key . endsWith ( 'gcc' ) ) ;
182
+ if ( gcc ) {
183
+ return toolLocations [ gcc ] . gdb ;
184
+ }
185
+ this . messageService . error ( 'Unable to find debugging tool: gdb' ) ;
186
+ return undefined ;
187
+ }
95
188
}
96
189
97
190
return boardsConfig . selectedBoard . name ;
98
191
}
99
192
100
- }
193
+ }
0 commit comments