Skip to content
This repository was archived by the owner on Oct 1, 2024. It is now read-only.

Commit c15dc08

Browse files
elektronikworkshopadiazulay
authored andcommitted
IntelliSense auto-analysis integration
* Reworked DeviceContext for fine grained event generation on settings change * Added dedicated settings classes which allows for the latter * Changed board manager and serial monitor to used the new fine grained events instead of the "something changed event" - which makes the code marginally more efficient * Implemented an analysis manager which takes care of analysis requests generated by settings change events and makes sure that analysis builds don't interfere with regular builds * Adapted the build infrastructure within ArduinoApp such that it allows for the above * Removed the global build guard and moved it to ArduinoApp (there is a corner case though for programmer selection within extension.ts which I marked with a TODO * Fixed some linting issues but did not lint most of the stuff committed here - this will be part of a later commit * I left notes here and there where I saw things which should/could be improved/changed * Removed the try/catch guards from the build invocations within extension.ts since exceptions are handled within the build function itself * Changed the project setting parameter for the IntelliSense setup to reflect its workings better
1 parent 548c714 commit c15dc08

13 files changed

+480
-260
lines changed

misc/arduinoValidator.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"type": "string",
3434
"minLength": 1
3535
},
36-
"disableIntelliSenseAutoGen": {
36+
"intelliSenseGen": {
3737
"description": "Disable/enable the automatic generation of the IntelliSense configuration file (c_cpp_properties.json) for this project (overrides the global setting). When set to \"global\" the global extension settings will be used.",
3838
"type": "string",
3939
"default": "global",

src/arduino/arduino.ts

+120-47
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import { DeviceContext } from "../deviceContext";
1515
import { IArduinoSettings } from "./arduinoSettings";
1616
import { BoardManager } from "./boardManager";
1717
import { ExampleManager } from "./exampleManager";
18-
import { ICoCoPaContext, isCompilerParserEnabled, makeCompilerParserContext } from "./intellisense";
18+
import { AnalysisManager,
19+
ICoCoPaContext,
20+
isCompilerParserEnabled,
21+
makeCompilerParserContext } from "./intellisense";
1922
import { LibraryManager } from "./libraryManager";
2023
import { VscodeSettings } from "./vscodeSettings";
2124

@@ -25,6 +28,11 @@ import { SerialMonitor } from "../serialmonitor/serialMonitor";
2528
import { UsbDetector } from "../serialmonitor/usbDetector";
2629
import { ProgrammerManager } from "./programmerManager";
2730

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+
*/
2836
export enum BuildMode {
2937
Verify = "Verifying",
3038
Analyze = "Analyzing",
@@ -45,10 +53,30 @@ export class ArduinoApp {
4553

4654
private _programmerManager: ProgrammerManager;
4755

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+
4871
/**
4972
* @param {IArduinoSettings} _settings ArduinoSetting object.
5073
*/
5174
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);
5280
}
5381

5482
/**
@@ -71,6 +99,17 @@ export class ArduinoApp {
7199
} catch (ex) {
72100
}
73101
}
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);
74113
}
75114

76115
/**
@@ -101,38 +140,96 @@ export class ArduinoApp {
101140
}
102141
}
103142

143+
/**
144+
* Returns true if a build is currently in progress.
145+
*/
146+
public get building() {
147+
return this._building;
148+
}
149+
104150
/**
105151
* Runs the arduino builder to build/compile and - if necessary - upload
106152
* 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.
111164
* @param {bool} compile - Indicates whether to compile the code when using the CLI to upload
112165
* @param buildDir Override the build directory set by the project settings
113166
* 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
114171
*/
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> {
116202
const dc = DeviceContext.getInstance();
117203
const args: string[] = [];
118204
let restoreSerialMonitor: boolean = false;
119205
let cocopa: ICoCoPaContext;
120206

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+
}
123211
return false;
124212
}
213+
const boardDescriptor = this.boardManager.currentBoard.getBuildConfig();
214+
125215
if (!this.useArduinoCli()) {
126216
args.push("--board", boardDescriptor);
127217
}
128218

129219
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.");
131221
return false;
132222
}
133223

134224
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+
}
136233
}
137234

138235
const selectSerial = async () => {
@@ -171,8 +268,9 @@ export class ArduinoApp {
171268
args.push("--port", dc.port);
172269
}
173270
} else if (buildMode === BuildMode.UploadProgrammer) {
174-
const programmer = this.getProgrammerString();
271+
const programmer = this.programmerManager.currentProgrammer;
175272
if (!programmer) {
273+
logger.notifyUserError("programmerManager.currentProgrammer", new Error(constants.messages.NO_PROGRAMMMER_SELECTED));
176274
return false;
177275
}
178276
if (!dc.port) {
@@ -205,9 +303,6 @@ export class ArduinoApp {
205303

206304
args.push("--port", dc.port);
207305
} else if (buildMode === BuildMode.Analyze) {
208-
if (!isCompilerParserEnabled()) {
209-
return false;
210-
}
211306
cocopa = makeCompilerParserContext(dc);
212307
if (!this.useArduinoCli()) {
213308
args.push("--verify", "--verbose");
@@ -229,6 +324,8 @@ export class ArduinoApp {
229324

230325
await vscode.workspace.saveAll(false);
231326

327+
// we prepare the channel here since all following code will
328+
// or at leas can possibly output to it
232329
arduinoChannel.show();
233330
arduinoChannel.start(`${buildMode} sketch '${dc.sketch}'`);
234331

@@ -716,7 +813,7 @@ export class ArduinoApp {
716813
const dc = DeviceContext.getInstance();
717814
const arduinoJson = {
718815
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?
720817
port: dc.port || "COM1",
721818
board: dc.board,
722819
configuration: dc.configuration,
@@ -818,14 +915,15 @@ export class ArduinoApp {
818915
* @returns True if successful, false on error.
819916
*/
820917
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();
825923
try {
826-
await util.spawn(prebuildCommand,
924+
await util.spawn(cmd,
827925
arduinoChannel.channel,
828-
prebuildargs,
926+
args,
829927
{ shell: true, cwd: ArduinoWorkspace.rootPath });
830928
} catch (ex) {
831929
arduinoChannel.error(`Running pre-build command failed: ${os.EOL}${ex.error}`);
@@ -843,30 +941,5 @@ export class ArduinoApp {
843941
return this._settings.useArduinoCli;
844942
// return VscodeSettings.getInstance().useArduinoCli;
845943
}
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 */
872945
}

src/arduino/boardManager.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ export class BoardManager {
7373
this._boardConfigStatusBar.show();
7474

7575
const dc = DeviceContext.getInstance();
76-
dc.onDidChange(() => {
76+
dc.onChangeBoard(() => {
77+
this.updateStatusBar();
78+
});
79+
dc.onChangeConfiguration(() => {
7780
this.updateStatusBar();
7881
});
7982
}

0 commit comments

Comments
 (0)