Commit 8d26516b authored by Timon Stampfli's avatar Timon Stampfli

telling vscode-cpptools Intellisense about soi.h

- bumping node version to 14
- bumping several dependencies
- adding regenerateSoiworkspaceConfig command
- some components are only initialized once a actual soi workspace is
  open
parent 89190ab1
Pipeline #5691 passed with stages
in 40 seconds
......@@ -25,7 +25,7 @@ build-release:
only:
- tags
stage: build
image: node:12
image: node:14
script:
- node ./setversion $CI_COMMIT_TAG
- npm ci
......
This diff is collapsed.
......@@ -114,6 +114,10 @@
{
"command": "soicode.toggleCompilerTimeout",
"title": "Enables/Disables compiler timeout of 10 sec"
},
{
"command": "soicode.regenerateWorkspaceConfig",
"title": "Regenerate the configuration of the soi workspace"
}
],
"properties": {},
......@@ -272,28 +276,24 @@
"webpack": "webpack --mode production"
},
"devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/fs-extra": "^8.0.1",
"@types/glob": "^7.1.1",
"@types/mocha": "^5.2.6",
"@types/node": "^10.12.21",
"@types/node": "^14.0.0",
"@types/vscode": "^1.33.0",
"glob": "^7.1.4",
"mocha": "^6.1.4",
"ts-loader": "^6.2.0",
"tslint": "^5.12.1",
"mocha": "^8.0.3",
"ts-loader": "^6.2.2",
"tslint": "^5.20.1",
"typescript": "^4.0.5",
"vsce": "^1.67.1",
"vscode-test": "^1.2.0",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9"
"vsce": "^1.81.1",
"vscode-jsonrpc": "^5.0.1",
"vscode-test": "^1.4.1",
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0"
},
"dependencies": {
"fs-extra": "^7.0.0",
"node-fetch": "^2.1.2",
"request-light": "^0.2.2",
"vscode-json-languageservice": "^3.1.0",
"vscode-languageclient": "^4.1.3",
"vscode-languageserver": "^4.1.2",
"vscode-nls": "^3.2.2"
"fs-extra": "^8.0.1",
"vscode-cpptools": "^4.0.1"
}
}
......@@ -4,26 +4,51 @@ import * as path from "path";
// import * as fs from "fs-extra";
// import * as https from "https";
import { getWorkspaceOrShowError } from "./storeHelper";
import { WorkspaceSettings } from "./soiworkspaceFormats/soiworkspace-0-8-0";
export function getCompilerPath(store: Store): string {
return getWorkspaceOrShowError(store).settings.settings.compilerPath;
export function getCompilerPath(w: WorkspaceSettings): string {
return w.settings.compilerPath;
}
export function getDebuggerPath(store: Store): string {
return getWorkspaceOrShowError(store).settings.settings.debuggerPath;
export function getDebuggerPath(w: WorkspaceSettings): string {
return w.settings.debuggerPath;
}
export function getDebuggerFlavor(store: Store): "gdb" | "lldb" | null {
let debuggerPath = getDebuggerPath(store);
export function getDebuggerFlavor(
w: WorkspaceSettings
): "gdb" | "lldb" | undefined {
let debuggerPath = getDebuggerPath(w);
if (debuggerPath === null) {
return null;
return undefined;
}
let flavor = path.basename(debuggerPath);
if (flavor === "gdb" || flavor === "lldb") {
return flavor;
}
return null;
return undefined;
}
export function getCppHeaderPath(store: Store): string {
export function getCompilerFlavor(
w: WorkspaceSettings
): "g++" | "clang++" | undefined {
let compilerPath = getCompilerPath(w);
if (compilerPath === null) {
return undefined;
}
let flavor = path.basename(compilerPath);
if (flavor === "g++" || flavor === "clang++") {
return flavor;
}
return undefined;
}
export function getCompilerTag(w: WorkspaceSettings) {
const compiler = getCompilerFlavor(w);
if (compiler === "clang++") {
return "clang-x64";
}
return "gcc-x64";
}
export function getCppHeaderPath(store: Store): string[] {
return getWorkspaceOrShowError(store).settings.settings.cppHeaderPath;
}
......
import { Store } from "./store";
import { determinePlatform } from "./util";
import * as child_process from "child_process";
import * as path from "path";
// import { EOL } from "os";
async function runCommand(
store: Store,
cmd: string,
args: string[]
): Promise<string | undefined> {
return new Promise(async resolve => {
// store.logInfo("Toolchain Discovery", `Finding Toolchain Path on ${platform}`);
let proc = child_process.execFile(cmd, args);
let stdout = "";
if (proc.stdout === null) {
return undefined;
}
proc.stdout.on("data", chunk => {
stdout += chunk;
});
proc.on("exit", (code, signal) => {
if (code !== 0) {
const msg = `Error running command '${cmd}' '${args}' stdout: '${stdout}'`;
store.logError("Compiler", msg);
resolve();
}
resolve(stdout);
});
});
}
export type ToolchainPaths = {
compilerPath: string;
debuggerPath: string;
cppHeaderPath: string[];
soiHeaderPath: string;
flags: string;
};
// function extractLibraries(store: Store, csd: string): string[] {
// let m = new Map<string, string[]>();
// for (const l of csd.split(EOL)) {
// const parts = l.split(":");
// if (parts.length < 2) {
// store.logError(
// "Parsing Compiler Libraries",
// `got invalid line in compiler search-dirs '${l}'`
// );
// continue;
// }
// let paths: string[] = [];
// for (const p of parts.slice(1)) {
// if (p.startsWith("=")) {
// paths.push(p.slice(1));
// } else {
// paths.push(p);
// }
// }
// m.set(parts[0], paths);
// }
// return m.get("libraries") || [];
// }
export async function discoverToolchain(store: Store): Promise<ToolchainPaths> {
let platform = determinePlatform(store);
let compilerPath = "";
let debuggerPath = "";
let cppHeaderPath: string[] = [];
let flags = "";
const soiHeaderPath = path.join(
store.soicodeExtensionDataPath,
"bundle",
"soiheaders",
"bundle",
"soiheader"
);
if (platform === "windows-amd64") {
return { ...getCompilerBundlePaths(store), soiHeaderPath };
}
// determine compilerpath
let cp = undefined;
// linux -> which g++
if (platform === "linux-amd64") {
cp = await runCommand(store, "which", ["g++"]);
if (cp !== undefined) {
compilerPath = cp.trim();
flags =
"-Wall -Wextra -std=c++17 -g3 -ggdb3 -fsanitize=address,undefined -D_GLIBCXX_DEBUG";
}
}
// macOs,linux -> which clang++
if (platform === "darwin-amd64" || cp === undefined) {
cp = await runCommand(store, "which", ["clang++"]);
if (cp !== undefined) {
compilerPath = cp.trim();
flags = "-Wall -Wextra -std=c++17 -g3 -ggdb3 -D_GLIBCXX_DEBUG";
}
}
// if (compilerPath !== "") {
// const out = await runCommand(store, compilerPath, ["--print-search-dirs"]);
// if (out !== undefined) {
// cppHeaderPath = extractLibraries(store, out);
// }
// }
// determine debuggerPath
let dp = undefined;
// linux -> which g++
if (platform === "linux-amd64") {
dp = await runCommand(store, "which", ["gdb"]);
if (dp !== undefined) {
debuggerPath = dp.trim();
}
}
// macOs,linux -> which clang++
if (platform === "darwin-amd64" || dp === undefined) {
dp = await runCommand(store, "which", ["lldb"]);
if (dp !== undefined) {
debuggerPath = dp.trim();
}
}
return { compilerPath, debuggerPath, cppHeaderPath, soiHeaderPath, flags };
}
function getCompilerBundlePaths(store: Store) {
return {
compilerPath: path.join(
store.soicodeExtensionDataPath,
"bundle",
"soiheaders",
"bundle",
"compiler",
"bin",
"g++.exe"
),
debuggerPath: "",
// cppHeaderPath: [
// path.join(
// store.soicodeExtensionDataPath,
// "bundle",
// "soiheaders",
// "bundle",
// "compiler",
// "include"
// )
// ],
cppHeaderPath: [""],
flags: "-Wall -Wextra -std=c++17 -g3 -ggdb3 -D_GLIBCXX_DEBUG"
};
}
import * as vscode from "vscode";
import * as cpt from "vscode-cpptools";
import { CancellationToken } from "vscode-jsonrpc";
import { Store } from "./store";
import * as path from "path";
import { getWorkspaceOrShowError } from "./storeHelper";
import {
getCompilationFlags,
getCompilerTag,
// getCppHeaderPath,
getSoiHeaderPath
} from "./compilerBundle";
export class CppConfigurationProvider
implements cpt.CustomConfigurationProvider {
store: Store;
constructor(store: Store) {
this.store = store;
}
checkReady(this: CppConfigurationProvider): boolean {
if (
this.store.workspace === "NoFolderOpen" ||
this.store.workspace === "NoSOIWorkspace"
) {
return false;
}
return true;
}
dispose() {}
async canProvideConfiguration(
uri: vscode.Uri,
token?: CancellationToken
): Promise<boolean> {
console.log("canProvideConfiguration");
if (!this.checkReady()) {
return false;
}
return path.extname(uri.fsPath) === ".cpp";
}
async provideConfigurations(
uris: vscode.Uri[],
token?: CancellationToken
): Promise<cpt.SourceFileConfigurationItem[]> {
console.log("provideConfiguration");
let workspace = getWorkspaceOrShowError(this.store);
try {
return uris.map(uri => {
return {
uri: uri,
configuration: {
includePath: [
// ...getCppHeaderPath(this.store),
getSoiHeaderPath(this.store)
],
defines: [],
intelliSenseMode: getCompilerTag(workspace.settings),
standard: "c++17",
forcedInclude: [getSoiHeaderPath(this.store)],
compilerPath: workspace.settings.settings.compilerPath
}
};
});
} catch (err) {
this.store.logError(
"Cpp Configuration Provider",
"failed providing a configuration",
err
);
return [];
}
}
async canProvideBrowseConfiguration(
token?: CancellationToken
): Promise<boolean> {
console.log("canProvideBrowseConfiguration");
return this.checkReady();
}
async provideBrowseConfiguration(
token?: CancellationToken
): Promise<cpt.WorkspaceBrowseConfiguration> {
console.log("provideBrowseConfiguration");
let workspace = getWorkspaceOrShowError(this.store);
return {
browsePath: [
// ...workspace.settings.settings.cppHeaderPath,
workspace.settings.settings.soiHeaderPath
],
compilerPath: workspace.settings.settings.compilerPath,
compilerArgs: getCompilationFlags(this.store),
standard: "c++17"
};
}
async canProvideBrowseConfigurationsPerFolder(
token?: CancellationToken
): Promise<boolean> {
console.log("canProvideBrowseConfiguration");
return this.checkReady();
}
async provideFolderBrowseConfiguration(
uri: vscode.Uri,
token?: CancellationToken
): Promise<cpt.WorkspaceBrowseConfiguration> {
console.log("provideFolderBrowseConfiguration");
let workspace = getWorkspaceOrShowError(this.store);
return {
browsePath: [
// ...workspace.settings.settings.cppHeaderPath,
workspace.settings.settings.soiHeaderPath
],
compilerPath: workspace.settings.settings.compilerPath,
compilerArgs: getCompilationFlags(this.store),
standard: "c++17"
};
}
readonly name = "soicode";
/** Our extension ID, visible to cpptools */
readonly extensionId = "swissolyinfo.soicode";
}
......@@ -3,7 +3,10 @@ import * as vscode from "vscode";
import { TaskTreeViewProvider } from "./taskTreeView";
import { SamplesTreeViewProvider } from "./samplesTreeView";
import { initializeWorkspace } from "./soiworkspace";
import {
initializeWorkspace,
regenerateWorkspaceSettings
} from "./soiworkspace";
import { createTask, createSoitaskFile, createCppFile } from "./soitask";
import {
insertCppTemplate,
......@@ -18,12 +21,12 @@ import { Store } from "./store";
import { HelperBinaryResultReceiver } from "./helperBinaryResultReceiver";
import { gotoSample } from "./sample";
import { downloadCompilerBundle } from "./helperBinary";
const port = 16314;
export async function activate(context: vscode.ExtensionContext) {
let store = new Store(context);
context.subscriptions.push(store);
let runner = new Runner(store, port);
let createTaskCommand = vscode.commands.registerCommand(
......@@ -110,6 +113,12 @@ export async function activate(context: vscode.ExtensionContext) {
);
context.subscriptions.push(toggleDisableCompilerTimeoutCommand);
let regenerateSoiworkspaceConfigCommand = vscode.commands.registerCommand(
"soicode.regenerateWorkspaceConfig",
regenerateWorkspaceSettings.bind(undefined, store)
);
context.subscriptions.push(regenerateSoiworkspaceConfigCommand);
let taskTreeViewProvider = new TaskTreeViewProvider(store);
let samplesTreeViewProvider = new SamplesTreeViewProvider(store);
......@@ -128,9 +137,6 @@ export async function activate(context: vscode.ExtensionContext) {
store.emitFsChange();
// await downloadHelperBinary(store);
await downloadCompilerBundle(store);
store.logInfo("soicode extension", "SOICode has been loaded");
}
......
......@@ -8,13 +8,13 @@ import { determinePlatform, executableFileEnding } from "./util";
export function getHelperPath(store: Store): string {
return path.join(
store.soicodeExtensionDistPath,
`helper-${determinePlatform()}${executableFileEnding()}`
`helper-${determinePlatform(store)}${executableFileEnding()}`
);
}
export async function downloadCompilerBundle(store: Store) {
return new Promise(async resolve => {
let platform = determinePlatform();
let platform = determinePlatform(store);
store.logInfo(
"Download Compiler Bundle",
"Fetching Helper binary for platform " + platform
......@@ -30,6 +30,9 @@ export async function downloadCompilerBundle(store: Store) {
targetDir
]);
let stdout = "";
if (proc.stdout === null) {
return undefined;
}
proc.stdout.on("data", chunk => {
stdout += chunk;
});
......
......@@ -47,13 +47,13 @@ export class Runner {
async compile(this: Runner, taskname: string): Promise<"Success" | "Failed"> {
return new Promise(async resolve => {
this.store.logInfo("compiler", `starting the compilation of ${taskname}`);
const workspace = getWorkspaceOrShowError(this.store).workspaceDir;
const workspace = getWorkspaceOrShowError(this.store);
const soitaskFiles = getSoitaskFilesOfFulltaskOrError(
this.store,
taskname
);
const compilerPath = getCompilerPath(this.store);
const compilerPath = getCompilerPath(workspace.settings);
let finished: vscode.Disposable[] = [];
let finishedTimeout: vscode.Disposable[] = [];
......@@ -126,13 +126,15 @@ export class Runner {
[
soitaskFiles.solutionWorkspacePath!,
...getCompilationFlags(this.store),
...headerAsFlag(getCppHeaderPath(this.store)),
...getCppHeaderPath(this.store)
.map(headerAsFlag)
.flat(),
...headerAsFlag(getSoiHeaderPath(this.store)),
"-o",
taskname
],
{
cwd: workspace
cwd: workspace.workspaceDir
}
);
......@@ -345,10 +347,10 @@ export class Runner {
return "Failed";
}
let workspace = getWorkspaceOrShowError(this.store).workspaceDir;
let workspace = getWorkspaceOrShowError(this.store);
let soitaskFiles = getSoitaskFilesOfFulltaskOrError(this.store, taskname);
let debuggerPath = getDebuggerPath(this.store);
let debuggerFlavor = getDebuggerFlavor(this.store);
let debuggerPath = getDebuggerPath(workspace.settings);
let debuggerFlavor = getDebuggerFlavor(workspace.settings);
if (debuggerPath === null) {
vscode.window.showErrorMessage("Debugger path could not be determined");
......@@ -363,7 +365,7 @@ export class Runner {
return "Failed";
}
if (debuggerFlavor === null) {
if (debuggerFlavor === undefined) {
vscode.window.showErrorMessage("Could not determine type of debugger");
return "Failed";
}
......@@ -375,7 +377,7 @@ export class Runner {
request: "launch",
program: soitaskFiles.binaryFsPath,
MiMode: debuggerFlavor,
cwd: workspace,
cwd: workspace.workspaceDir,
setupCommands: [
{
description: "Enable pretty-printing for debugger",
......
......@@ -9,6 +9,12 @@ import {
soiWorkspaceTemplate_0_8_0,
checkIsWorkspaceSettings
} from "./soiworkspaceFormats/soiworkspace-0-8-0";
import {
getCompilerFlavor,
getCompilerPath,
getDebuggerFlavor,
getDebuggerPath
} from "./compilerBundle";
export type SoiWorkspace = {
task: Map<string, SoitaskFiles>;
......@@ -55,30 +61,51 @@ async function determineWorkspaceSettingsFileContent(
async function createWorkspaceSettingsFileContent(
store: Store,
workspace: string
): Promise<"failed" | "success"> {
): Promise<"failed" | WorkspaceSettings> {
let workspaceSettings = await vscode.workspace.findFiles("soiworkspace.json");
if (workspaceSettings.length >= 2 || workspaceSettings.length < 0) {
if (workspaceSettings.length >= 1 || workspaceSettings.length < 0) {
// Todo: Replace with assert
// throw new Error("This is impossible");
return "failed";
}
if (workspaceSettings.length === 0) {
try {
await fs.writeFile(
path.join(workspace, "soiworkspace.json"),
soiWorkspaceTemplate_0_8_0(store)
);
} catch (err) {
vscode.window.showErrorMessage(
"Error initializing workspace: " + err.toString()
);
return "failed";
}
try {
await fs.writeFile(
path.join(workspace, "soiworkspace.json"),
await soiWorkspaceTemplate_0_8_0(store)
);
} catch (err) {
vscode.window.showErrorMessage(
"Error initializing workspace: " + err.toString()
);
return "failed";
}
const sett = await determineWorkspaceSettings(store, workspace);
return sett || "failed";
}
async function regenerateWorkspaceSettingsFileContent(
store: Store,
workspace: string
): Promise<"failed" | WorkspaceSettings> {
let workspaceSettings = await vscode.workspace.findFiles("soiworkspace.json");
if (workspaceSettings.length >= 2 || workspaceSettings.length <= 0) {
// Todo: Replace with assert
// throw new Error("This is impossible");
return "failed";
}
if ((await determineWorkspaceSettings(store, workspace)) === null) {
try {
await fs.writeFile(
path.join(workspace, "soiworkspace.json"),
await soiWorkspaceTemplate_0_8_0(store)
);
} catch (err) {
vscode.window.showErrorMessage(
"Error initializing workspace: " + err.toString()
);
return "failed";
}
return "success";
const sett = await determineWorkspaceSettings(store, workspace);
return sett || "failed";
}
async function determineWorkspaceSettings(
......@@ -124,12 +151,38 @@ export async function readWorkspaceState(
};
}
function printWorkspaceSettingsInfo(w: WorkspaceSettings) {
const msg = `Successfully created soiworkspace settings file, with the following settings
compiler:'${getCompilerFlavor(w)}'
debuger:'${getDebuggerFlavor(w)}'
compilerPath:'${getCompilerPath(w)}'