-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a Meson cpptools configProvider #218
Changes from all commits
df23bd0
f0f791a
29ae13d
6eb5995
571b796
f3535fb
10094cb
fac5db2
3af2d02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import * as vscode from "vscode"; | ||
import * as cpptools from "vscode-cpptools"; | ||
import { getMesonBuildOptions, getMesonCompilers, getMesonDependencies } from "./introspection"; | ||
import { getOutputChannel } from "./utils"; | ||
import { Compiler, Dependencies } from "./types"; | ||
|
||
export class CpptoolsProvider implements cpptools.CustomConfigurationProvider { | ||
cppToolsAPI?: cpptools.CppToolsApi; | ||
private buildDir: string; | ||
|
||
constructor(buildDir: string) { | ||
this.buildDir = buildDir; | ||
} | ||
|
||
name = "Meson Build"; | ||
extensionId = "mesonbuild.mesonbuild"; | ||
|
||
canProvideBrowseConfiguration(token?: vscode.CancellationToken | undefined): Thenable<boolean> { | ||
return new Promise<boolean>((resolve) => { | ||
if (this.buildDir !== "") { | ||
resolve(true); | ||
} else { | ||
// Wait for this.buildDir to not be "" | ||
const interval = setInterval(() => { | ||
if (this.buildDir !== "") { | ||
clearInterval(interval); | ||
this.refresh(this.buildDir); | ||
resolve(true); | ||
} | ||
}, 100); | ||
} | ||
}); | ||
} | ||
|
||
async provideBrowseConfiguration( | ||
token?: vscode.CancellationToken | undefined, | ||
): Promise<cpptools.WorkspaceBrowseConfiguration | null> { | ||
let browseConfig: cpptools.WorkspaceBrowseConfiguration = { | ||
browsePath: [], | ||
compilerPath: "${default}", | ||
compilerArgs: [], | ||
}; | ||
|
||
const dependencies = await getMesonDependencies(this.buildDir); | ||
browseConfig = Object.assign(browseConfig, { browsePath: this.getDependenciesIncludeDirs(dependencies) }); | ||
|
||
let machine: string | undefined; | ||
const buildOptions = await getMesonBuildOptions(this.buildDir); | ||
for (const option of buildOptions) { | ||
if (option.name === "cpp_std") { | ||
if (option.value != "none") browseConfig = Object.assign({}, browseConfig, { standard: option.value }); | ||
machine = option.machine; | ||
} else if (machine === undefined && option.name === "c_std") { | ||
// C++ takes precedence | ||
if (option.value != "none") browseConfig = Object.assign({}, browseConfig, { standard: option.value }); | ||
machine = option.machine; | ||
} | ||
} | ||
|
||
try { | ||
const compilers = await getMesonCompilers(this.buildDir); | ||
if (machine !== undefined && compilers[machine] !== undefined) { | ||
const compiler = compilers[machine]; | ||
if (compiler && compiler["cpp"]) { | ||
browseConfig = this.setCompilerArgs(compiler, "cpp", browseConfig); | ||
} else if (compiler && compiler["c"]) { | ||
browseConfig = this.setCompilerArgs(compiler, "c", browseConfig); | ||
} | ||
} | ||
} catch (e) { | ||
getOutputChannel().appendLine( | ||
`Could not introspect a specific compiler, the default one will be used: ${JSON.stringify(e)}`, | ||
); | ||
} | ||
|
||
getOutputChannel().appendLine(`Providing cpptools configuration: ${JSON.stringify(browseConfig)}`); | ||
return browseConfig; | ||
} | ||
|
||
private getDependenciesIncludeDirs(dependencies: Dependencies) { | ||
let includeDirs: string[] = []; | ||
for (const dep of dependencies) { | ||
if (dep.compile_args) { | ||
for (const arg of dep.compile_args) { | ||
if (arg.startsWith("-I")) { | ||
includeDirs.push(arg.slice(2)); | ||
} | ||
} | ||
} | ||
} | ||
// The cpptools API requires at least one browse path, even when we provide a compiler path. | ||
if (includeDirs.length === 0) { | ||
includeDirs.push(""); | ||
} | ||
return includeDirs; | ||
} | ||
|
||
private setCompilerArgs( | ||
compiler: Compiler, | ||
standard: string, | ||
browseConfig: cpptools.WorkspaceBrowseConfiguration, | ||
): cpptools.WorkspaceBrowseConfiguration { | ||
if (compiler[standard]) { | ||
const compilerDesc = compiler[standard]; | ||
browseConfig = Object.assign({}, browseConfig, { | ||
compilerPath: compilerDesc.exelist[0], | ||
compilerArgs: compilerDesc.exelist.slice(1), | ||
}); | ||
} | ||
return browseConfig; | ||
} | ||
|
||
// We only handle project-wide configurations. | ||
canProvideBrowseConfigurationsPerFolder(token?: vscode.CancellationToken | undefined): Thenable<boolean> { | ||
return Promise.resolve(false); | ||
} | ||
|
||
async provideFolderBrowseConfiguration( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whitespace around functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
uri: vscode.Uri, | ||
token?: vscode.CancellationToken | undefined, | ||
): Promise<cpptools.WorkspaceBrowseConfiguration | null> { | ||
return null; | ||
} | ||
|
||
// We only handle project-wide configurations. | ||
canProvideConfiguration(uri: vscode.Uri, token?: vscode.CancellationToken | undefined): Thenable<boolean> { | ||
return Promise.resolve(false); | ||
} | ||
|
||
async provideConfigurations( | ||
uris: vscode.Uri[], | ||
token?: vscode.CancellationToken | undefined, | ||
): Promise<cpptools.SourceFileConfigurationItem[]> { | ||
return []; | ||
} | ||
|
||
dispose() {} | ||
|
||
refresh(buildDir: string) { | ||
this.buildDir = buildDir; | ||
this.cppToolsAPI?.notifyReady(this); | ||
this.cppToolsAPI?.didChangeCustomConfiguration(this); | ||
this.cppToolsAPI?.didChangeCustomBrowseConfiguration(this); | ||
} | ||
} | ||
|
||
// Official implementation from https://classic.yarnpkg.com/en/package/vscode-cpptools | ||
export async function registerCppToolsProvider( | ||
ctx: vscode.ExtensionContext, | ||
provider: CpptoolsProvider, | ||
): Promise<cpptools.CppToolsApi | undefined> { | ||
const cppToolsAPI = await cpptools.getCppToolsApi(cpptools.Version.latest); | ||
if (cppToolsAPI) { | ||
provider.cppToolsAPI = cppToolsAPI; | ||
if (cppToolsAPI.notifyReady) { | ||
cppToolsAPI.registerCustomConfigurationProvider(provider); | ||
cppToolsAPI.notifyReady(provider); | ||
ctx.subscriptions.push(cppToolsAPI); | ||
} else { | ||
throw new Error("CppTools API not available, or not version >2.0"); | ||
} | ||
} | ||
return cppToolsAPI; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,16 +15,19 @@ import { | |
} from "./utils"; | ||
import { DebugConfigurationProviderCppdbg } from "./debug/cppdbg"; | ||
import { DebugConfigurationProviderLldb } from "./debug/lldb"; | ||
import { CpptoolsProvider, registerCppToolsProvider } from "./cpptoolsconfigprovider"; | ||
import { testDebugHandler, testRunHandler, rebuildTests } from "./tests"; | ||
import { activateLinters } from "./linters"; | ||
import { activateFormatters } from "./formatters"; | ||
import { SettingsKey, TaskQuickPickItem } from "./types"; | ||
import { createLanguageServerClient } from "./lsp/common"; | ||
import { askShouldDownloadLanguageServer, askConfigureOnOpen, askAndSelectRootDir, selectRootDir } from "./dialogs"; | ||
import { getIntrospectionFile } from "./introspection"; | ||
|
||
export let extensionPath: string; | ||
export let workspaceState: vscode.Memento; | ||
let explorer: MesonProjectExplorer; | ||
let cpptools: CpptoolsProvider; | ||
let watcher: vscode.FileSystemWatcher; | ||
let controller: vscode.TestController; | ||
|
||
|
@@ -69,6 +72,8 @@ export async function activate(ctx: vscode.ExtensionContext) { | |
const buildDir = getBuildDirectory(sourceDir); | ||
workspaceState.update("mesonbuild.buildDir", buildDir); | ||
workspaceState.update("mesonbuild.sourceDir", sourceDir); | ||
cpptools = new CpptoolsProvider(buildDir); | ||
registerCppToolsProvider(ctx, cpptools); | ||
Comment on lines
+75
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we only do this if it is a C or C++ project? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it matters. If the user does not add the |
||
|
||
explorer = new MesonProjectExplorer(ctx, sourceDir, buildDir); | ||
|
||
|
@@ -149,6 +154,15 @@ export async function activate(ctx: vscode.ExtensionContext) { | |
} | ||
}); | ||
|
||
const mesonInfoFile = getIntrospectionFile(buildDir, "meson-info.json"); | ||
whenFileExists(ctx, mesonInfoFile, async () => { | ||
cpptools.refresh(buildDir); | ||
if (shouldModifySetting("ms-vscode.cpptools")) { | ||
const conf = vscode.workspace.getConfiguration("C_Cpp"); | ||
conf.update("default.configurationProvider", "mesonbuild.mesonbuild", vscode.ConfigurationTarget.Workspace); | ||
} | ||
}); | ||
|
||
ctx.subscriptions.push( | ||
vscode.commands.registerCommand("mesonbuild.openBuildFile", async (node: TargetNode) => { | ||
const file = node.getTarget().defined_in; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It needs to be accessed by registerCppToolsProvider