Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fa4c5d1
Generate a C/C++ build task
grdowns Jan 15, 2019
bf31fe6
Cleaning
grdowns Jan 15, 2019
a5d3354
Move args into definition
grdowns Jan 16, 2019
02af719
Add args to shellexecution to allow calling the task without first co…
grdowns Jan 16, 2019
20a0520
Read compiler paths sent in defaults to generate task list
grdowns Jan 22, 2019
d81ba1e
Rename compilerPaths to compilerInfo; Filter tasks based on file exte…
grdowns Jan 24, 2019
31d5fc3
Use our own file extension filters to decide whether tasks are presented
grdowns Jan 25, 2019
e807b54
Show dialog when no compilers are found
grdowns Jan 25, 2019
5eede83
Display a message if no compilers are found
grdowns Jan 25, 2019
8a95801
Add compilerPath getter to config; Use it to offer another task
grdowns Jan 28, 2019
5c66968
Refactoring; Commenting
grdowns Jan 28, 2019
a3605fb
Remove CompilerInfo namespace; Formatting; Change return vals
grdowns Jan 29, 2019
0734201
Commenting; Add telemetry; Inverse condition
grdowns Jan 29, 2019
dac9b22
Change output program based on OS; Remove message and collect telemet…
grdowns Jan 30, 2019
d244b8f
Filter out redundant compiler entries
grdowns Jan 30, 2019
3f888ef
Remove TODO; Get proper exe name; Properly reassign compilerPaths aft…
grdowns Jan 30, 2019
f7a595f
Commenting; Fix cwd mingw bug
grdowns Jan 30, 2019
7ca5f9b
Commenting; Refactor
grdowns Jan 30, 2019
e282c1f
Mark compilerInfo const
grdowns Jan 30, 2019
61cfd4f
Remove whitespace; Remove bad comment
grdowns Jan 30, 2019
ca2daea
Remove whitespace
grdowns Jan 30, 2019
0adc132
Replace unique algorithm with a map
grdowns Jan 30, 2019
e180fee
pre-compute basename
grdowns Jan 30, 2019
459322d
Move comment
grdowns Jan 31, 2019
2f94cc4
Commenting; Ensure user's compilerPath setting is used
grdowns Jan 31, 2019
898f679
Use indexOf instead of find
grdowns Jan 31, 2019
a27bb84
Simplify isHeader calculation by using some instead of every
grdowns Jan 31, 2019
81d75a5
Don't redundantly check extensions; Use some instead of indexOf
grdowns Jan 31, 2019
9dd16c3
Merge branch 'master' into grdowns/build-templates
grdowns Jan 31, 2019
3d2db78
Merge branch 'master' into grdowns/build-templates
sean-mcmanus Feb 1, 2019
7079099
Add comment punctuation
grdowns Feb 1, 2019
1c5c42b
Merge branch 'grdowns/build-templates' of https://github.com/Microsof…
grdowns Feb 6, 2019
a9a0794
Lowercase file extension to match; Count extensionless files as headers
grdowns Feb 6, 2019
751ac0f
Merge branch 'master' into grdowns/build-templates
grdowns Feb 6, 2019
7b4fad4
Add newline
grdowns Feb 6, 2019
296387a
Merge branch 'grdowns/build-templates' of https://github.com/Microsof…
grdowns Feb 6, 2019
b234685
Change CompilerInfo to KnownCompiler
grdowns Feb 11, 2019
16a06b6
Support ambiguous file extension
grdowns Feb 11, 2019
4908e57
Merge branch 'master' into grdowns/build-templates
grdowns Feb 11, 2019
ce4e5da
Early out for extensionless files
grdowns Feb 11, 2019
1f657f8
Merge branch 'grdowns/build-templates' of https://github.com/Microsof…
grdowns Feb 11, 2019
024a0eb
Commenting
grdowns Feb 11, 2019
58cd0bc
Commenting; Rename telemetry event
grdowns Feb 12, 2019
0ec7b4f
Change languageAssociation to isC
grdowns Feb 13, 2019
26da4db
Fix bug where cwd was not used; Add comment
grdowns Feb 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@
],
"main": "./out/src/main",
"contributes": {
"taskDefinitions": [
{
"type": "shell",
"properties": {
"label": {
"type": "string"
},
"command": {
"type": "string"
},
"args": {
"type": "array"
},
"options": {
"type": "array"
}
}
}
],
"problemMatchers": [
{
"name": "gcc",
Expand Down
12 changes: 12 additions & 0 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ export interface Client {
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void>;
provideCustomConfiguration(document: vscode.TextDocument): Promise<void>;
getCurrentConfigName(): Thenable<string>;
getCompilerPath(): Thenable<string>;
getKnownCompilers(): Thenable<configs.KnownCompiler[]>;
takeOwnership(document: vscode.TextDocument): void;
queueTask<T>(task: () => Thenable<T>): Thenable<T>;
requestWhenReady(request: () => Thenable<any>): Thenable<any>;
Expand Down Expand Up @@ -662,6 +664,14 @@ class DefaultClient implements Client {
return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfiguration.name));
}

public getCompilerPath(): Thenable<string> {
return this.queueTask(() => Promise.resolve(this.configuration.CompilerPath));
}

public getKnownCompilers(): Thenable<configs.KnownCompiler[]> {
return this.queueTask(() => Promise.resolve(this.configuration.KnownCompiler));
}

/**
* Take ownership of a document that was previously serviced by another client.
* This process involves sending a textDocument/didOpen message to the server so
Expand Down Expand Up @@ -1350,6 +1360,8 @@ class NullClient implements Client {
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
provideCustomConfiguration(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
getCurrentConfigName(): Thenable<string> { return Promise.resolve(""); }
getCompilerPath(): Thenable<string> { return Promise.resolve(""); }
getKnownCompilers(): Thenable<configs.KnownCompiler[]> { return Promise.resolve([]); }
takeOwnership(document: vscode.TextDocument): void {}
queueTask<T>(task: () => Thenable<T>): Thenable<T> { return task(); }
requestWhenReady(request: () => Thenable<any>): Thenable<any> { return; }
Expand Down
14 changes: 14 additions & 0 deletions Extension/src/LanguageServer/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface ConfigurationJson {
export interface Configuration {
name: string;
compilerPath?: string;
knownCompilers?: KnownCompiler[];
cStandard?: string;
cppStandard?: string;
includePath?: string[];
Expand All @@ -65,8 +66,14 @@ export interface Browse {
databaseFilename?: string;
}

export interface KnownCompiler {
path: string;
isC: boolean;
}

export interface CompilerDefaults {
compilerPath: string;
knownCompilers: KnownCompiler[];
cStandard: string;
cppStandard: string;
includes: string[];
Expand All @@ -85,6 +92,7 @@ export class CppProperties {
private configFileWatcherFallbackTime: Date = new Date(); // Used when file watching fails.
private compileCommandFileWatchers: fs.FSWatcher[] = [];
private defaultCompilerPath: string = null;
private knownCompilers: KnownCompiler[] = null;
private defaultCStandard: string = null;
private defaultCppStandard: string = null;
private defaultIncludes: string[] = null;
Expand Down Expand Up @@ -147,6 +155,8 @@ export class CppProperties {
public get Configurations(): Configuration[] { return this.configurationJson.configurations; }
public get CurrentConfigurationIndex(): number { return this.currentConfigurationIndex.Value; }
public get CurrentConfiguration(): Configuration { return this.Configurations[this.CurrentConfigurationIndex]; }
public get CompilerPath(): string { return this.CurrentConfiguration.compilerPath; }
public get KnownCompiler(): KnownCompiler[] { return this.knownCompilers; }

public get CurrentConfigurationProvider(): string|null {
if (this.CurrentConfiguration.configurationProvider) {
Expand All @@ -163,6 +173,7 @@ export class CppProperties {

public set CompilerDefaults(compilerDefaults: CompilerDefaults) {
this.defaultCompilerPath = compilerDefaults.compilerPath;
this.knownCompilers = compilerDefaults.knownCompilers;
this.defaultCStandard = compilerDefaults.cStandard;
this.defaultCppStandard = compilerDefaults.cppStandard;
this.defaultIncludes = compilerDefaults.includes;
Expand Down Expand Up @@ -248,6 +259,9 @@ export class CppProperties {
// don't set a default when compileCommands is in use.
configuration.compilerPath = this.defaultCompilerPath;
}
if (this.knownCompilers) {
configuration.knownCompilers = this.knownCompilers;
}
if (isUnset(settings.defaultCStandard) && this.defaultCStandard) {
configuration.cStandard = this.defaultCStandard;
}
Expand Down
144 changes: 144 additions & 0 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Range } from 'vscode-languageclient';
import { ChildProcess, spawn, execSync } from 'child_process';
import * as tmp from 'tmp';
import { getTargetBuildInfo } from '../githubAPI';
import * as configs from './configurations';
import { PackageVersion } from '../packageVersion';

let prevCrashFile: string;
Expand All @@ -37,6 +38,8 @@ let tempCommands: vscode.Disposable[] = [];
let activatedPreviously: PersistentWorkspaceState<boolean>;
const insiderUpdateTimerInterval: number = 1000 * 60 * 60;

let taskProvider: vscode.Disposable;

/**
* activate: set up the extension for language services
*/
Expand All @@ -60,6 +63,21 @@ export function activate(activationEventOccurred: boolean): void {
return;
}

taskProvider = vscode.tasks.registerTaskProvider('C/Cpp', {
provideTasks: () => {
return getBuildTasks();
},
resolveTask(task: vscode.Task): vscode.Task {
// Currently cannot implement because VS Code does not call this. Can implement custom output file directory when enabled.
return undefined;
}
});
vscode.tasks.onDidStartTask(event => {
if (event.execution.task.source === 'C/Cpp') {
telemetry.logLanguageServerEvent('buildTaskStarted');
}
});

// handle "workspaceContains:/.vscode/c_cpp_properties.json" activation event.
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
for (let i: number = 0; i < vscode.workspace.workspaceFolders.length; ++i) {
Expand All @@ -83,6 +101,129 @@ export function activate(activationEventOccurred: boolean): void {
}
}

/**
* Generate tasks to build the current file based on the user's detected compilers, the user's compilerPath setting, and the current file's extension.
*/
async function getBuildTasks(): Promise<vscode.Task[]> {
const editor: vscode.TextEditor = vscode.window.activeTextEditor;
if (!editor) {
return [];
}

const fileExt: string = path.extname(editor.document.fileName);
if (!fileExt) {
return;
}

// Don't offer tasks for header files.
const fileExtLower: string = fileExt.toLowerCase();
const isHeader: boolean = !fileExt || [".hpp", ".hh", ".hxx", ".h", ""].some(ext => fileExtLower === ext);
if (isHeader) {
return [];
}

// Don't offer tasks if the active file's extension is not a recognized C/C++ extension.
let fileIsCpp: boolean;
let fileIsC: boolean;
if (fileExt === ".C") { // ".C" file extensions are both C and C++.
fileIsCpp = true;
fileIsC = true;
} else {
fileIsCpp = [".cpp", ".cc", ".cxx", ".mm", ".ino", ".inl"].some(ext => fileExtLower === ext);
fileIsC = fileExtLower === ".c";
}
if (!(fileIsCpp || fileIsC)) {
return [];
}

// Get a list of compilers found from the C++ side, then filter them based on the file type to get a reduced list appropriate
// for the active file, remove duplicate compiler names, then finally add the user's compilerPath setting.
let compilerPaths: string[];
const activeClient: Client = getActiveClient();
const userCompilerPath: string = await activeClient.getCompilerPath();
let knownCompilers: configs.KnownCompiler[] = await activeClient.getKnownCompilers();
if (knownCompilers) {
knownCompilers = knownCompilers.filter(info => { return (fileIsCpp && !info.isC) || (fileIsC && info.isC); });
compilerPaths = knownCompilers.map<string>(info => { return info.path; });

let map: Map<string, string> = new Map<string, string>();
const insertOrAssignEntry: (compilerPath: string) => void = (compilerPath: string): void => {
const basename: string = path.basename(compilerPath);
map.has(basename) ? map[basename] = compilerPath : map.set(basename, compilerPath);
};
compilerPaths.forEach(insertOrAssignEntry);

// Ensure that the user's compilerPath setting is used by inserting/assigning last.
if (userCompilerPath) {
insertOrAssignEntry(userCompilerPath);
}

compilerPaths = [...map.values()];
} else if (userCompilerPath) {
compilerPaths = [userCompilerPath];
}

if (!compilerPaths) {
// Don't prompt a message yet until we can make a data-based decision.
telemetry.logLanguageServerEvent('noCompilerFound');
// Display a message prompting the user to install compilers if none were found.
// const dontShowAgain: string = "Don't Show Again";
// const learnMore: string = "Learn More";
// const message: string = "No C/C++ compiler found on the system. Please install a C/C++ compiler to use the C/Cpp: build active file tasks.";

// let showNoCompilerFoundMessage: PersistentState<boolean> = new PersistentState<boolean>("CPP.showNoCompilerFoundMessage", true);
// if (showNoCompilerFoundMessage) {
// vscode.window.showInformationMessage(message, learnMore, dontShowAgain).then(selection => {
// switch (selection) {
// case learnMore:
// const uri: vscode.Uri = vscode.Uri.parse(`https://go.microsoft.com/fwlink/?linkid=864631`);
// vscode.commands.executeCommand('vscode.open', uri);
// break;
// case dontShowAgain:
// showNoCompilerFoundMessage.Value = false;
// break;
// default:
// break;
// }
// });
// }
return [];
}

// The build task output file should include a '.exe' extension on Windows.
let platformInfo: PlatformInformation = await PlatformInformation.GetPlatformInformation();
let exeName: string;
if (platformInfo.platform === 'win32') {
exeName = '${fileBasenameNoExtension}.exe';
} else {
exeName = '${fileBasenameNoExtension}';
}

// Generate tasks.
let result: vscode.Task[] = [];
compilerPaths.forEach(compilerPath => {
const taskName: string = path.basename(compilerPath) + " build active file";
const args: string[] = ['-g', '${file}', '-o', '${fileDirname}/' + exeName];
const cwd: string = path.dirname(compilerPath);
const kind: vscode.TaskDefinition = {
type: 'shell',
label: taskName,
command: compilerPath,
args: args,
options: {"cwd": cwd}
};

const command: vscode.ShellExecution = new vscode.ShellExecution(compilerPath, [...args], { cwd: cwd });
const target: vscode.WorkspaceFolder = vscode.workspace.getWorkspaceFolder(clients.ActiveClient.RootUri);
let task: vscode.Task = new vscode.Task(kind, target, taskName, 'C/Cpp', command, '$gcc');
task.definition = kind; // The constructor for vscode.Task will eat the definition. Reset it by reassigning.
task.group = vscode.TaskGroup.Build;

result.push(task);
});
return result;
}

function onDidOpenTextDocument(document: vscode.TextDocument): void {
if (document.languageId === "c" || document.languageId === "cpp") {
onActivationEvent();
Expand Down Expand Up @@ -727,6 +868,9 @@ export function deactivate(): Thenable<void> {
disposables.forEach(d => d.dispose());
languageConfigurations.forEach(d => d.dispose());
ui.dispose();
if (taskProvider) {
taskProvider.dispose();
}
return clients.dispose();
}

Expand Down