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

Commit

Permalink
Forceinclude Arduino.h
Browse files Browse the repository at this point in the history
* Added message to end of each build to inform user how to update the IntelliSense configuration
* The magic now searches all identified include paths for the Arduino core include file (aka Arduino.h) and adds it as forced include - most users expect Arduino core functionality to work without having to include this header. Added typed-promisify to dependencies since I made use of it in the new code for better readability.
* Conclude is now asynchronous
* Updated branch status and added new future task
* Bumped cocopa version to 0.0.10
  • Loading branch information
elektronikworkshop authored and adiazulay committed Jan 19, 2021
1 parent b7effbc commit f2a5307
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 18 deletions.
12 changes: 7 additions & 5 deletions BRANCHNOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,19 @@ During merging I found some bugs within those functions - mainly due to the abov
| | :heavy_check_mark: Merging of parsing result and existing file content |
| | :heavy_check_mark: Handling inexistent files and folders |
| | :heavy_check_mark: Write configuration on change only |
| | :white_check_mark: Option to backup old configurations? |
| **Configuration flags** | :heavy_check_mark: Provide global disable flag for IntelliSense auto-config |
| | :heavy_check_mark: Provide project specific override for the global flag - most users will likely use the default setup and disable auto-generation for very specific projects |
| **Unit tests** | :heavy_check_mark: Basic parser (known boards, match/no match)|
| | :white_check_mark: All unit tests in cocopa |
| | :white_check_mark: Test with cpp sketches |
| **General** | :heavy_check_mark: Review and remove previous attempts messing with `c_cpp_properties.json` or IntelliSense (documented in the [General Tasks](#General-Tasks) section) `*` |
| | :white_check_mark: *Auto-run verify when* |
| | :heavy_check_mark: *Auto-run verify when* |
| |     :heavy_check_mark: a) setting a board `*` |
| |     :heavy_check_mark: b) changing the board's configuration `*` |
| |     :heavy_check_mark: c) selecting another sketch `*` |
| |     :white_check_mark: d) workbench initialized and no `c_cpp_properties.json` found |
| |     :white_check_mark: e) Identify other occasions where this applies (usually when adding new libraries) |
| | :white_check_mark: Hint the user to run *Arduino: Rebuild IntelliSense Configuration*? -> Good moment would be after the workbench initialization -> message in arduino channel |
| |     :heavy_check_mark: d) ~~workbench initialized and no `c_cpp_properties.json` found~~ obsolete: when board and board configuration is loaded on start up the analysis is triggered anyways |
| |     :white_check_mark: e) Identify other occasions where this applies (usually when adding new libraries) -- any suggestions? |
| | :heavy_check_mark: Hint the user to run *Arduino: Rebuild IntelliSense Configuration* -> printing message after each build (verify, upload, ...) |
| | :heavy_check_mark: Better build management such that regular builds and analyze builds do not interfere (done, 2020-02-19) `*` |
| | :heavy_check_mark: Analyze task queue which fits in the latter (done, 2020-02-19) `*` |
| | :heavy_check_mark: Document configuration settings in [README.md](README.md) |
Expand Down Expand Up @@ -214,6 +213,9 @@ I will list every supporter here, thanks!
* When having adding a library folder to the workspace IntelliSense should use the same configuration for it to enable library navigation and code completion.
* Optimization: Abort analysis build as soon as compiler statement has been found
* Non-IDE unit testing - to eliminate dependency injection use ts-mock-imports for instance
* Hardcoded and scattered constants:
* Load package.json and use values from therein instead of hard coding redundant values like shortcuts (like I did for the IntelliSense message in `arduino.ts`)
* Scan code for other hard coded stuff and take appropriate countermeasures

## Non-categorized Notes
### Integrate upstream changes into fork
Expand Down
11 changes: 8 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@
},
"dependencies": {
"body-parser": "^1.16.1",
"cocopa": "^0.0.9",
"cocopa": "^0.0.10",
"compare-versions": "^3.4.0",
"eventemitter2": "^4.1.0",
"express": "^4.14.1",
Expand All @@ -613,6 +613,7 @@
"impor": "^0.1.1",
"node-usb-native": "^0.0.18",
"properties": "^1.2.1",
"typed-promisify": "^0.4.0",
"uuid": "^3.0.1",
"vscode-extension-telemetry": "0.1.6",
"winreg": "^1.2.3",
Expand Down
18 changes: 12 additions & 6 deletions src/arduino/arduino.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ export class ArduinoApp {

const cleanup = async () => {
if (cocopa) {
cocopa.conclude();
await cocopa.conclude();
}
if (buildMode === BuildMode.Upload || buildMode === BuildMode.UploadProgrammer) {
UsbDetector.getInstance().resumeListening();
Expand Down Expand Up @@ -399,15 +399,21 @@ export class ArduinoApp {
stdoutCallback,
).then(async () => {
await cleanup();
if (buildMode !== BuildMode.Analyze) {
const cmd = os.platform() === "darwin"
? "Cmd + Alt + I"
: "Ctrl + Alt + I";
arduinoChannel.info(`To rebuild your IntelliSense configuration run "${cmd}"`);
}
arduinoChannel.end(`${buildMode} sketch '${dc.sketch}'${os.EOL}`);
success = true;
}, async (reason) => {
await cleanup();
const msg = reason.code ?
`Exit with code=${reason.code}` :
reason.message ?
reason.message :
JSON.stringify(reason);
const msg = reason.code
? `Exit with code=${reason.code}`
: reason.message
? reason.message
: JSON.stringify(reason);
arduinoChannel.error(`${buildMode} sketch '${dc.sketch}': ${msg}${os.EOL}`);
});

Expand Down
63 changes: 60 additions & 3 deletions src/arduino/intellisense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// Licensed under the MIT license.

import * as ccp from "cocopa";
import * as fs from "fs";
import * as path from "path";
import * as tp from "typed-promisify";

import * as constants from "../common/constants";
import { arduinoChannel } from "../common/outputChannel";
Expand All @@ -13,7 +15,7 @@ import { VscodeSettings } from "./vscodeSettings";

export interface ICoCoPaContext {
callback: (s: string) => void;
conclude: () => void;
conclude: () => Promise<void>;
};

/**
Expand Down Expand Up @@ -58,7 +60,7 @@ export function makeCompilerParserContext(dc: DeviceContext): ICoCoPaContext {
const runner = new ccp.Runner(engines);

// Set up the callback to be called after parsing
const _conclude = () => {
const _conclude = async () => {
if (!runner.result) {
arduinoChannel.warning("Failed to generate IntelliSense configuration.");
return;
Expand All @@ -67,14 +69,26 @@ export function makeCompilerParserContext(dc: DeviceContext): ICoCoPaContext {
// Normalize compiler and include paths (resolve ".." and ".")
runner.result.normalize();

// Search for Arduino.h in the include paths - we need it for a
// forced include - users expect Arduino symbols to be available
// in main sketch without having to include the header explicitly
const ardHeader = await locateArduinoHeader(runner.result.includes);
const forcedIncludes = ardHeader
? [ ardHeader ]
: undefined;
if (!ardHeader) {
arduinoChannel.warning("Unable to locate \"Arduino.h\" within IntelliSense include paths.");
}

// TODO: check what kind of result we've got: gcc or other architecture:
// and instantiate content accordingly (to be implemented within cocopa)
const content = new ccp.CCppPropertiesContentResult(runner.result,
"Arduino",
ccp.CCppPropertiesISMode.Gcc_X64,
ccp.CCppPropertiesCStandard.C11,
// as of 1.8.11 arduino is on C++11
ccp.CCppPropertiesCppStandard.Cpp11);
ccp.CCppPropertiesCppStandard.Cpp11,
forcedIncludes);
try {
const pPath = path.join(ArduinoWorkspace.rootPath, constants.CPP_CONFIG_FILE);
const prop = new ccp.CCppProperties();
Expand Down Expand Up @@ -113,6 +127,49 @@ function makeCompilerParserEngines(dc: DeviceContext) {
return [gccParserEngine];
}

/**
* Search directories recursively for a file.
* @param dir Directory where the search should begin.
* @param what The file we're looking for.
* @returns The path of the directory which contains the file else undefined.
*/
async function findDirContaining(dir: string, what: string): Promise<string | undefined> {
const readdir = tp.promisify(fs.readdir);
const fsstat = tp.promisify(fs.stat);

for (const entry of await readdir(dir)) {
const p = path.join(dir, entry);
const s = await fsstat(p);
if (s.isDirectory()) {
const result = await findDirContaining(p, what);
if (result) {
return result;
}
} else if (entry === what) {
return dir;
}
}
return undefined;
};

/**
* Tries to find the main Arduino header (i.e. Arduino.h) in the given include
* paths.
* @param includes Array containing all include paths in which we should look
* for Arduino.h
* @returns The full path of the main Arduino header.
*/
async function locateArduinoHeader(includes: string[]) {
const header = "Arduino.h";
for (const i of includes) {
const result = await findDirContaining(i, header);
if (result) {
return path.join(result, header);
}
}
return undefined;
}

/**
* Possible states of AnalysisManager's state machine.
*/
Expand Down

0 comments on commit f2a5307

Please sign in to comment.