Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions Build/package/jobs_package_vsix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ parameters:
- name: srcDir
type: string
default: ''
- name: signType
type: string
default: 'real'

jobs:
- job: package
displayName: Build ${{ parameters.vsixName }}
timeoutInMinutes: 30
cancelTimeoutInMinutes: 1
templateContext:
mb: # Enable the MicroBuild Signing toolset
signing:
enabled: true
signType: ${{ parameters.signType }}
zipSources: false
${{ if eq(parameters.signType, 'real') }}:
signWithProd: true
featureFlags:
autoBaseline: false
outputs:
- output: pipelineArtifact
displayName: '${{ parameters.vsixName }}'
Expand Down
24 changes: 12 additions & 12 deletions Extension/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,25 @@ jobs/**
cgmanifest.json

# ignore development files
tsconfig.json
test.tsconfig.json
ui.tsconfig.json
tslint.json
.eslintignore
.eslintrc.js
webpack.config.js
tscCompileList.txt
gulpfile.js
.gitattributes
.gitignore
gulpfile.js
localized_string_ids.h
readme.developer.md
Reinstalling the Extension.md
test.tsconfig.json
translations_auto_pr.js
tsconfig.json
tslint.json
tscCompileList.txt
ui.tsconfig.json
webpack.config.js
CMakeLists.txt
debugAdapters/install.lock*
typings/**
**/*.map
import_edge_strings.js
localized_string_ids.h
translations_auto_pr.js
readme.developer.md
Reinstalling the Extension.md
*.d.ts

# ignore i18n language files
Expand Down
6 changes: 6 additions & 0 deletions Extension/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# C/C++ for Visual Studio Code Changelog

## Version 1.28.1: October 6, 2025
### Bug Fixes
* Fix extension activation getting stuck when certain SSH config files are processed (by the SSH targets view feature). [#13966](https://github.com/microsoft/vscode-cpptools/issues/13966)
* Fix document symbols randomly showing previous versions of symbols after they are modified. [#13967](https://github.com/microsoft/vscode-cpptools/issues/13967)
* A potential fix for a crash.

## Version 1.28.0: September 25, 2025
### Enhancements
* Add IntelliSense support for c23 `bool`, `true`, and `false`. [#13737](https://github.com/microsoft/vscode-cpptools/issues/13737)
Expand Down
2 changes: 1 addition & 1 deletion Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "cpptools",
"displayName": "C/C++",
"description": "C/C++ IntelliSense, debugging, and code browsing.",
"version": "1.28.0-main",
"version": "1.28.1-main",
"publisher": "ms-vscode",
"icon": "LanguageCCPP_color_128x.png",
"readme": "README.md",
Expand Down
1 change: 1 addition & 0 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,7 @@ export class DefaultClient implements Client {
}

this.copilotCompletionProvider = CopilotCompletionContextProvider.Create();
util.setProgress(util.getProgressCopilotSuccess());
this.disposables.push(this.copilotCompletionProvider);

// Listen for messages from the language server.
Expand Down
69 changes: 53 additions & 16 deletions Extension/src/SSH/sshHosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,28 +99,64 @@ export async function getSshConfiguration(configurationPath: string, resolveIncl
return config;
}

async function resolveConfigIncludes(config: Configuration, configPath: string): Promise<void> {
for (const entry of config) {
if (isDirective(entry) && entry.param === 'Include') {
let includePath: string = resolveHome(entry.value);
if (isWindows && !!includePath.match(/^\/[a-z]:/i)) {
includePath = includePath.substr(1);
}

if (!path.isAbsolute(includePath)) {
includePath = path.resolve(path.dirname(configPath), includePath);
}

const pathsToGetFilesFrom: string[] = await globAsync(includePath);
function getProcessedPathKey(filePath: string): string {
const absolutePath: string = path.resolve(filePath);
const normalizedPath: string = path.normalize(absolutePath);
return isWindows ? normalizedPath.toLowerCase() : normalizedPath;
}

for (const filePath of pathsToGetFilesFrom) {
await getIncludedConfigFile(config, filePath);
async function resolveConfigIncludes(
config: Configuration,
configPath: string,
processedIncludePaths?: Set<string>,
processedIncludeEntries?: WeakSet<ConfigurationDirective>
): Promise<void> {
processedIncludePaths = processedIncludePaths ?? new Set<string>();
processedIncludeEntries = processedIncludeEntries ?? new WeakSet<ConfigurationDirective>();
const configKey: string = getProcessedPathKey(configPath);
if (processedIncludePaths.has(configKey)) {
return;
}
processedIncludePaths.add(configKey);
try {
for (const entry of config) {
if (isDirective(entry) && entry.param === 'Include') {
// Prevent duplicate expansion of the same Include directive within a single resolution pass.
if (processedIncludeEntries.has(entry)) {
continue;
}
processedIncludeEntries.add(entry);
let includePath: string = resolveHome(entry.value);
if (isWindows && !!includePath.match(/^\/[a-z]:/i)) {
includePath = includePath.slice(1);
}

if (!path.isAbsolute(includePath)) {
includePath = path.resolve(path.dirname(configPath), includePath);
}

const pathsToGetFilesFrom: string[] = await globAsync(includePath);

for (const filePath of pathsToGetFilesFrom) {
const includeKey: string = getProcessedPathKey(filePath);
if (processedIncludePaths.has(includeKey)) {
continue;
}
await getIncludedConfigFile(config, filePath, processedIncludePaths, processedIncludeEntries);
}
}
}
} finally {
processedIncludePaths.delete(configKey);
}
}

async function getIncludedConfigFile(config: Configuration, includePath: string): Promise<void> {
async function getIncludedConfigFile(
config: Configuration,
includePath: string,
processedIncludePaths: Set<string>,
processedIncludeEntries: WeakSet<ConfigurationDirective>
): Promise<void> {
let includedContents: string;
try {
includedContents = (await fs.readFile(includePath)).toString();
Expand All @@ -136,6 +172,7 @@ async function getIncludedConfigFile(config: Configuration, includePath: string)
getSshChannel().appendLine(localize("failed.to.parse.SSH.config", "Failed to parse SSH configuration file {0}: {1}", includePath, (err as Error).message));
return;
}
await resolveConfigIncludes(parsedIncludedContents, includePath, processedIncludePaths, processedIncludeEntries);
config.push(...parsedIncludedContents);
}

Expand Down
25 changes: 17 additions & 8 deletions Extension/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,19 +247,22 @@ export function displayExtensionNotReadyPrompt(): void {
// Users start with a progress of 0 and it increases as they get further along in using the tool.
// This eliminates noise/problems due to re-installs, terminated installs that don't send errors,
// errors followed by workarounds that lead to success, etc.
const progressInstallSuccess: number = 100;
const progressDebuggerStarted: number = 50;
const progressDebuggerSuccess: number = 100;
const progressExecutableStarted: number = 150;
const progressCopilotSuccess: number = 180;
const progressExecutableSuccess: number = 200;
const progressParseRootSuccess: number = 300;
const progressLanguageServiceDisabled: number = 400;
const progressIntelliSenseNoSquiggles: number = 1000;
// Might add more IntelliSense progress measurements later.
// IntelliSense progress is separate from the install progress, because parse root can occur afterwards.
// IntelliSense progress is separate from the activation progress, because parse root can occur afterwards.

const installProgressStr: string = "CPP." + packageJson.version + ".Progress";
const activationProgressStr: string = "CPP." + packageJson.version + ".Progress";
const intelliSenseProgressStr: string = "CPP." + packageJson.version + ".IntelliSenseProgress";

export function getProgress(): number {
return extensionContext ? extensionContext.globalState.get<number>(installProgressStr, -1) : -1;
return extensionContext ? extensionContext.globalState.get<number>(activationProgressStr, -1) : -1;
}

export function getIntelliSenseProgress(): number {
Expand All @@ -268,15 +271,18 @@ export function getIntelliSenseProgress(): number {

export function setProgress(progress: number): void {
if (extensionContext && getProgress() < progress) {
void extensionContext.globalState.update(installProgressStr, progress);
void extensionContext.globalState.update(activationProgressStr, progress);
const telemetryProperties: Record<string, string> = {};
let progressName: string | undefined;
switch (progress) {
case 0: progressName = "install started"; break;
case progressInstallSuccess: progressName = "install succeeded"; break;
case 0: progressName = "activation started"; break;
case progressDebuggerStarted: progressName = "debugger started"; break;
case progressDebuggerSuccess: progressName = "debugger succeeded"; break;
case progressExecutableStarted: progressName = "executable started"; break;
case progressCopilotSuccess: progressName = "copilot succeeded"; break;
case progressExecutableSuccess: progressName = "executable succeeded"; break;
case progressParseRootSuccess: progressName = "parse root succeeded"; break;
case progressLanguageServiceDisabled: progressName = "language service disabled"; break;
}
if (progressName) {
telemetryProperties.progress = progressName;
Expand All @@ -300,10 +306,13 @@ export function setIntelliSenseProgress(progress: number): void {
}
}

export function getProgressInstallSuccess(): number { return progressInstallSuccess; } // Download/install was successful (i.e. not blocked by component acquisition).
export function getProgressDebuggerStarted(): number { return progressDebuggerStarted; } // Debugger initialization was started.
export function getProgressDebuggerSuccess(): number { return progressDebuggerSuccess; } // Debugger was successfully initialized.
export function getProgressExecutableStarted(): number { return progressExecutableStarted; } // The extension was activated and starting the executable was attempted.
export function getProgressCopilotSuccess(): number { return progressCopilotSuccess; } // Copilot activation was successful.
export function getProgressExecutableSuccess(): number { return progressExecutableSuccess; } // Starting the exe was successful (i.e. not blocked by 32-bit or glibc < 2.18 on Linux)
export function getProgressParseRootSuccess(): number { return progressParseRootSuccess; } // Parse root was successful (i.e. not blocked by processing taking too long).
export function getProgressLanguageServiceDisabled(): number { return progressLanguageServiceDisabled; } // The user disabled the language service.
export function getProgressIntelliSenseNoSquiggles(): number { return progressIntelliSenseNoSquiggles; } // IntelliSense was successful and the user got no squiggles.

export function isUri(input: any): input is vscode.Uri {
Expand Down
5 changes: 4 additions & 1 deletion Extension/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
});

util.setExtensionContext(context);
Telemetry.activate();
util.setProgress(0);
Telemetry.activate();

// Register a protocol handler to serve localized versions of the schema for c_cpp_properties.json
class SchemaProvider implements vscode.TextDocumentContentProvider {
Expand All @@ -63,7 +63,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
vscode.workspace.registerTextDocumentContentProvider('cpptools-schema', instrument(new SchemaProvider()));

// Initialize the DebuggerExtension and register the related commands and providers.
util.setProgress(util.getProgressDebuggerStarted());
await DebuggerExtension.initialize(context);
util.setProgress(util.getProgressDebuggerSuccess());

const info: PlatformInformation = await PlatformInformation.GetPlatformInformation();
sendTelemetry(info);
Expand Down Expand Up @@ -161,6 +163,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
// The check here for isIntelliSenseEngineDisabled avoids logging
// the message on old Macs that we've already displayed a warning for.
log(localize("intellisense.disabled", "intelliSenseEngine is disabled"));
util.setProgress(util.getProgressLanguageServiceDisabled());
}

// Send an instrumentation message upon completing activation.
Expand Down
7 changes: 0 additions & 7 deletions ExtensionPack/CHANGELOG.md

This file was deleted.

16 changes: 16 additions & 0 deletions ExtensionPack/package-lock.json

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

2 changes: 1 addition & 1 deletion ExtensionPack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"name": "Microsoft Corporation"
},
"license": "SEE LICENSE IN LICENSE.txt",
"version": "1.3.1",
"version": "1.4.0",
"engines": {
"vscode": "^1.48.0"
},
Expand Down
1 change: 0 additions & 1 deletion Themes/.gitignore

This file was deleted.

16 changes: 16 additions & 0 deletions Themes/package-lock.json

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

2 changes: 1 addition & 1 deletion Themes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "cpptools-themes",
"displayName": "C/C++ Themes",
"description": "UI Themes for C/C++ extension.",
"version": "2.0.0",
"version": "2.1.0",
"publisher": "ms-vscode",
"preview": false,
"icon": "assets/LanguageCCPP_color_128x.png",
Expand Down