Skip to content

Register restore commands even if DevKit is being used #8428

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1849,13 +1849,13 @@
"command": "dotnet.restore.project",
"title": "%command.dotnet.restore.project%",
"category": ".NET",
"enablement": "dotnet.server.activationContext == 'Roslyn' || dotnet.server.activationContext == 'OmniSharp'"
"enablement": "dotnet.server.activationContext == 'RoslynDevKit' || dotnet.server.activationContext == 'Roslyn' || dotnet.server.activationContext == 'OmniSharp'"
},
{
"command": "dotnet.restore.all",
"title": "%command.dotnet.restore.all%",
"category": ".NET",
"enablement": "dotnet.server.activationContext == 'Roslyn' || dotnet.server.activationContext == 'OmniSharp'"
"enablement": "dotnet.server.activationContext == 'RoslynDevKit' || dotnet.server.activationContext == 'Roslyn' || dotnet.server.activationContext == 'OmniSharp'"
},
{
"command": "csharp.listProcess",
Expand Down
52 changes: 45 additions & 7 deletions src/lsptoolshost/projectRestore/restore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,65 @@ import { getCSharpDevKit } from '../../utils/getCSharpDevKit';
let _restoreInProgress = false;

export function registerRestoreCommands(context: vscode.ExtensionContext, languageServer: RoslynLanguageServer) {
if (getCSharpDevKit()) {
// We do not need to register restore commands if using C# devkit.
return;
}
const restoreChannel = vscode.window.createOutputChannel(vscode.l10n.t('.NET NuGet Restore'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to very unfortunately create a second nuget restore channel. Other than having devkit do the restore though I don't have a great alternative. But we should get an issue filed on this at the very least.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use the C# log for the time being? Had the O# extension not separated them, I am not sure I would have the distinction. OR, possibly I would have put all project system logging into the restore one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would actually be to put these in the C# log. When we split across output windows it just becomes harder to tell the order that things occur in. Even when there are timestamps (which I am adding in this PR.)

However to reduce scope I am going to refrain from renaming or moving which output channel we use here.

Also, what is l10n? Is this just a super weird abbreviation? An 'l' then 10 letters then an 'n' to make 'localization'?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n 'l' then 10 letters then an 'n' to make 'localization'?

Yup!

Copy link
Member

@dibarbet dibarbet Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, lets do the C# window then. Better than a duplicate output window.

context.subscriptions.push(
vscode.commands.registerCommand('dotnet.restore.project', async (_request): Promise<void> => {
if (getCSharpDevKit()) {
appendLineWithTimestamp(
restoreChannel,
"Not handling command 'dotnet.restore.project' from C# extension, because C# Dev Kit is expected to handle it."
);
return;
}

return chooseProjectAndRestore(languageServer, restoreChannel);
})
);
context.subscriptions.push(
vscode.commands.registerCommand('dotnet.restore.all', async (): Promise<void> => {
if (getCSharpDevKit()) {
appendLineWithTimestamp(
restoreChannel,
"Not handling command 'dotnet.restore.all' from C# extension, because C# Dev Kit is expected to handle it."
);
return;
}

return restore(languageServer, restoreChannel, [], true);
})
);

languageServer.registerOnRequest(ProjectNeedsRestoreRequest.type, async (params) => {
await restore(languageServer, restoreChannel, params.projectFilePaths, false);
let projectFilePaths = params.projectFilePaths;
if (getCSharpDevKit()) {
// Only restore '.cs' files (file-based apps) if CDK is loaded.
const csharpFiles = [];
for (const path of projectFilePaths) {
if (path.endsWith('.cs')) {
csharpFiles.push(path);
} else {
appendLineWithTimestamp(
restoreChannel,
`Not restoring '${path}' from C# extension, because C# Dev Kit is expected to handle restore for it.`
);
}
}

projectFilePaths = csharpFiles;
}

if (projectFilePaths.length > 0) {
await restore(languageServer, restoreChannel, params.projectFilePaths, false);
}
});
}

function appendLineWithTimestamp(outputChannel: vscode.OutputChannel, line: string) {
// Match the timestamp format used in the language server
const dateString = new Date().toISOString().replace('T', ' ').replace('Z', '');
outputChannel.appendLine(`${dateString} ${line}`);
}

async function chooseProjectAndRestore(
languageServer: RoslynLanguageServer,
restoreChannel: vscode.OutputChannel
Expand Down Expand Up @@ -101,7 +139,7 @@ export async function restore(
async (progress, token) => {
const writeOutput = (output: RestorePartialResult) => {
if (output.message) {
restoreChannel.appendLine(output.message);
appendLineWithTimestamp(restoreChannel, output.message);
}

progress.report({ message: output.stage });
Expand All @@ -117,7 +155,7 @@ export async function restore(

await responsePromise.then(
(result) => result.forEach((r) => writeOutput(r)),
(err) => restoreChannel.appendLine(err)
(err) => appendLineWithTimestamp(restoreChannel, err)
);
}
)
Expand Down
9 changes: 3 additions & 6 deletions test/lsptoolshost/integrationTests/expectedCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@ const CommonCommands = [
'csharp.listRemoteDockerProcess',
'csharp.attachToProcess',
'csharp.reportIssue',
];

// Commands used by both O# and Roslyn standalone activation contexts.
const CommonStandaloneCommands = [
'dotnet.restore.project',
'dotnet.restore.all',
'dotnet.test.runTestsInContext',
'dotnet.test.debugTestsInContext',
];

// Commands used by both O# and Roslyn standalone activation contexts.
const CommonStandaloneCommands = ['dotnet.test.runTestsInContext', 'dotnet.test.debugTestsInContext'];

// Commands used only in an O# activation context.
const OmniSharpOnlyCommands = [
'o.restart',
Expand Down
Loading