@@ -15,7 +15,10 @@ import { DeviceContext } from "../deviceContext";
15
15
import { IArduinoSettings } from "./arduinoSettings" ;
16
16
import { BoardManager } from "./boardManager" ;
17
17
import { ExampleManager } from "./exampleManager" ;
18
- import { ICoCoPaContext , isCompilerParserEnabled , makeCompilerParserContext } from "./intellisense" ;
18
+ import { AnalysisManager ,
19
+ ICoCoPaContext ,
20
+ isCompilerParserEnabled ,
21
+ makeCompilerParserContext } from "./intellisense" ;
19
22
import { LibraryManager } from "./libraryManager" ;
20
23
import { VscodeSettings } from "./vscodeSettings" ;
21
24
@@ -25,6 +28,11 @@ import { SerialMonitor } from "../serialmonitor/serialMonitor";
25
28
import { UsbDetector } from "../serialmonitor/usbDetector" ;
26
29
import { ProgrammerManager } from "./programmerManager" ;
27
30
31
+ /**
32
+ * Supported build modes. For further explanation see the documentation
33
+ * of ArduinoApp.build().
34
+ * The strings are used for status reporting within the above function.
35
+ */
28
36
export enum BuildMode {
29
37
Verify = "Verifying" ,
30
38
Analyze = "Analyzing" ,
@@ -45,10 +53,30 @@ export class ArduinoApp {
45
53
46
54
private _programmerManager : ProgrammerManager ;
47
55
56
+ /**
57
+ * IntelliSense analysis manager.
58
+ * Makes sure that analysis builds and regular builds go along
59
+ * and that multiple subsequent analysis requests - as triggered
60
+ * by board/board-configuration changes - are bundled to a single
61
+ * analysis build run.
62
+ */
63
+ private _analysisManager : AnalysisManager ;
64
+
65
+ /**
66
+ * Indicates if a build is currently in progress.
67
+ * If so any call to this.build() will return false immediately.
68
+ */
69
+ private _building : boolean = false ;
70
+
48
71
/**
49
72
* @param {IArduinoSettings } _settings ArduinoSetting object.
50
73
*/
51
74
constructor ( private _settings : IArduinoSettings ) {
75
+ const analysisDelayMs = 1000 * 3 ;
76
+ this . _analysisManager = new AnalysisManager (
77
+ ( ) => this . _building ,
78
+ async ( ) => { await this . build ( BuildMode . Analyze , true ) ; } ,
79
+ analysisDelayMs ) ;
52
80
}
53
81
54
82
/**
@@ -71,6 +99,17 @@ export class ArduinoApp {
71
99
} catch ( ex ) {
72
100
}
73
101
}
102
+
103
+ // set up event handling for IntelliSense analysis
104
+ const requestAnalysis = async ( ) => {
105
+ if ( isCompilerParserEnabled ( ) ) {
106
+ await this . _analysisManager . requestAnalysis ( ) ;
107
+ }
108
+ } ;
109
+ const dc = DeviceContext . getInstance ( ) ;
110
+ dc . onChangeBoard ( requestAnalysis ) ;
111
+ dc . onChangeConfiguration ( requestAnalysis ) ;
112
+ dc . onChangeSketch ( requestAnalysis ) ;
74
113
}
75
114
76
115
/**
@@ -101,38 +140,96 @@ export class ArduinoApp {
101
140
}
102
141
}
103
142
143
+ /**
144
+ * Returns true if a build is currently in progress.
145
+ */
146
+ public get building ( ) {
147
+ return this . _building ;
148
+ }
149
+
104
150
/**
105
151
* Runs the arduino builder to build/compile and - if necessary - upload
106
152
* the current sketch.
107
- * @param buildMode Build mode. BuildMode.Upload: Compile and upload,
108
- * BuildMode.UploadProgrammer: Compile and upload using the user selectable
109
- * programmer, BuildMode.Analyze: Compile, analyze the output and generate
110
- * IntelliSense configuration from it, BuildMode.Verify: Just compile.
153
+ * @param buildMode Build mode.
154
+ * * BuildMode.Upload: Compile and upload
155
+ * * BuildMode.UploadProgrammer: Compile and upload using the user
156
+ * selectable programmer
157
+ * * BuildMode.Analyze: Compile, analyze the output and generate
158
+ * IntelliSense configuration from it.
159
+ * * BuildMode.Verify: Just compile.
160
+ * All build modes except for BuildMode.Analyze run interactively, i.e. if
161
+ * something is missing, it tries to query the user for the missing piece
162
+ * of information (sketch, board, etc.). Analyze runs non interactively and
163
+ * just returns false.
111
164
* @param {bool } compile - Indicates whether to compile the code when using the CLI to upload
112
165
* @param buildDir Override the build directory set by the project settings
113
166
* with the given directory.
167
+ * @returns true on success, false if
168
+ * * another build is currently in progress
169
+ * * board- or programmer-manager aren't initialized yet
170
+ * * or something went wrong during the build
114
171
*/
115
- public async build ( buildMode : BuildMode , compile : boolean , buildDir ?: string ) : Promise < boolean > {
172
+ public async build ( buildMode : BuildMode , compile : boolean , buildDir ?: string ) {
173
+
174
+ if ( ! this . _boardManager || ! this . _programmerManager || this . _building ) {
175
+ return false ;
176
+ }
177
+
178
+ this . _building = true ;
179
+
180
+ return await this . _build ( buildMode , compile , buildDir )
181
+ . then ( ( ret ) => {
182
+ this . _building = false ;
183
+ return ret ;
184
+ } )
185
+ . catch ( ( reason ) => {
186
+ this . _building = false ;
187
+ // TODO EW, 2020-02-19: Report unhandled error (Logger?)
188
+ return false ;
189
+ } ) ;
190
+ }
191
+
192
+ // Not moving _build around in the file (yet?) because it would create too much merge/rebase problems.
193
+ /* tslint:disable:member-ordering */
194
+
195
+ /**
196
+ * Private implementation. Not to be called directly. The wrapper build()
197
+ * manages the build state.
198
+ * @param buildMode See build()
199
+ * @param buildDir See build()
200
+ */
201
+ public async _build ( buildMode : BuildMode , compile : boolean , buildDir ?: string ) : Promise < boolean > {
116
202
const dc = DeviceContext . getInstance ( ) ;
117
203
const args : string [ ] = [ ] ;
118
204
let restoreSerialMonitor : boolean = false ;
119
205
let cocopa : ICoCoPaContext ;
120
206
121
- const boardDescriptor = this . getBoardBuildString ( ) ;
122
- if ( ! boardDescriptor ) {
207
+ if ( ! this . boardManager . currentBoard ) {
208
+ if ( buildMode !== BuildMode . Analyze ) {
209
+ logger . notifyUserError ( "boardManager.currentBoard" , new Error ( constants . messages . NO_BOARD_SELECTED ) ) ;
210
+ }
123
211
return false ;
124
212
}
213
+ const boardDescriptor = this . boardManager . currentBoard . getBuildConfig ( ) ;
214
+
125
215
if ( ! this . useArduinoCli ( ) ) {
126
216
args . push ( "--board" , boardDescriptor ) ;
127
217
}
128
218
129
219
if ( ! ArduinoWorkspace . rootPath ) {
130
- vscode . window . showWarningMessage ( "Cannot find the sketch file ." ) ;
220
+ vscode . window . showWarningMessage ( "Workspace doesn't seem to have a folder added to it yet ." ) ;
131
221
return false ;
132
222
}
133
223
134
224
if ( ! dc . sketch || ! util . fileExistsSync ( path . join ( ArduinoWorkspace . rootPath , dc . sketch ) ) ) {
135
- await this . getMainSketch ( dc ) ;
225
+ if ( buildMode === BuildMode . Analyze ) {
226
+ // Analyze runs non interactively
227
+ return false ;
228
+ }
229
+ if ( ! await dc . resolveMainSketch ( ) ) {
230
+ vscode . window . showErrorMessage ( "No sketch file was found. Please specify the sketch in the arduino.json file" ) ;
231
+ return false ;
232
+ }
136
233
}
137
234
138
235
const selectSerial = async ( ) => {
@@ -171,8 +268,9 @@ export class ArduinoApp {
171
268
args . push ( "--port" , dc . port ) ;
172
269
}
173
270
} else if ( buildMode === BuildMode . UploadProgrammer ) {
174
- const programmer = this . getProgrammerString ( ) ;
271
+ const programmer = this . programmerManager . currentProgrammer ;
175
272
if ( ! programmer ) {
273
+ logger . notifyUserError ( "programmerManager.currentProgrammer" , new Error ( constants . messages . NO_PROGRAMMMER_SELECTED ) ) ;
176
274
return false ;
177
275
}
178
276
if ( ! dc . port ) {
@@ -205,9 +303,6 @@ export class ArduinoApp {
205
303
206
304
args . push ( "--port" , dc . port ) ;
207
305
} else if ( buildMode === BuildMode . Analyze ) {
208
- if ( ! isCompilerParserEnabled ( ) ) {
209
- return false ;
210
- }
211
306
cocopa = makeCompilerParserContext ( dc ) ;
212
307
if ( ! this . useArduinoCli ( ) ) {
213
308
args . push ( "--verify" , "--verbose" ) ;
@@ -229,6 +324,8 @@ export class ArduinoApp {
229
324
230
325
await vscode . workspace . saveAll ( false ) ;
231
326
327
+ // we prepare the channel here since all following code will
328
+ // or at leas can possibly output to it
232
329
arduinoChannel . show ( ) ;
233
330
arduinoChannel . start ( `${ buildMode } sketch '${ dc . sketch } '` ) ;
234
331
@@ -716,7 +813,7 @@ export class ArduinoApp {
716
813
const dc = DeviceContext . getInstance ( ) ;
717
814
const arduinoJson = {
718
815
sketch : sketchFile ,
719
- // TODO: COM1 is Windows specific - what about OSX and Linux users?
816
+ // TODO EW, 2020-02-18 : COM1 is Windows specific - what about OSX and Linux users?
720
817
port : dc . port || "COM1" ,
721
818
board : dc . board ,
722
819
configuration : dc . configuration ,
@@ -818,14 +915,15 @@ export class ArduinoApp {
818
915
* @returns True if successful, false on error.
819
916
*/
820
917
protected async runPreBuildCommand ( dc : DeviceContext ) : Promise < boolean > {
821
- if ( dc . prebuild ) {
822
- arduinoChannel . info ( `Running pre-build command: ${ dc . prebuild } ` ) ;
823
- const prebuildargs = dc . prebuild . split ( " " ) ;
824
- const prebuildCommand = prebuildargs . shift ( ) ;
918
+ const prebuildcmdline = dc . prebuild ;
919
+ if ( prebuildcmdline ) {
920
+ arduinoChannel . info ( `Running pre-build command: ${ prebuildcmdline } ` ) ;
921
+ const args = prebuildcmdline . split ( / \s + / ) ;
922
+ const cmd = args . shift ( ) ;
825
923
try {
826
- await util . spawn ( prebuildCommand ,
924
+ await util . spawn ( cmd ,
827
925
arduinoChannel . channel ,
828
- prebuildargs ,
926
+ args ,
829
927
{ shell : true , cwd : ArduinoWorkspace . rootPath } ) ;
830
928
} catch ( ex ) {
831
929
arduinoChannel . error ( `Running pre-build command failed: ${ os . EOL } ${ ex . error } ` ) ;
@@ -843,30 +941,5 @@ export class ArduinoApp {
843
941
return this . _settings . useArduinoCli ;
844
942
// return VscodeSettings.getInstance().useArduinoCli;
845
943
}
846
-
847
- private getProgrammerString ( ) : string {
848
- const selectProgrammer = this . programmerManager . currentProgrammer ;
849
- if ( ! selectProgrammer ) {
850
- logger . notifyUserError ( "getProgrammerString" , new Error ( constants . messages . NO_PROGRAMMMER_SELECTED ) ) ;
851
- return ;
852
- }
853
- return selectProgrammer ;
854
- }
855
-
856
- private getBoardBuildString ( ) : string {
857
- const selectedBoard = this . boardManager . currentBoard ;
858
- if ( ! selectedBoard ) {
859
- logger . notifyUserError ( "getBoardBuildString" , new Error ( constants . messages . NO_BOARD_SELECTED ) ) ;
860
- return ;
861
- }
862
- return selectedBoard . getBuildConfig ( ) ;
863
- }
864
-
865
- private async getMainSketch ( dc : DeviceContext ) {
866
- await dc . resolveMainSketch ( ) ;
867
- if ( ! dc . sketch ) {
868
- vscode . window . showErrorMessage ( "No sketch file was found. Please specify the sketch in the arduino.json file" ) ;
869
- throw new Error ( "No sketch file was found." ) ;
870
- }
871
- }
944
+ /* tslint:enable:member-ordering */
872
945
}
0 commit comments